Skip to content

Commit 6781cc6

Browse files
authored
Header과 Navigation이 렌더링되지 않던 버그 수정 (#226)
* HeaderContent 대신 ContentHeader과 CoverableRoute를 각각 props로 받게 변경 * Navigation 구조에서 child.prop로 가져오던 부분을 context로 변경함 * NavigationArea가 남아 있던 버그 수정 - key 값이 남아있는 듯 함 * 레오 리뷰 반영 * React.Children.map 에 null escape 조건 추가
1 parent bda20f9 commit 6781cc6

File tree

13 files changed

+160
-129
lines changed

13 files changed

+160
-129
lines changed

src/contexts/NavigationContext.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* External dependencies */
2+
import { createContext } from 'react'
3+
import { noop } from 'lodash-es'
4+
5+
export interface NavigationContextProps {
6+
optionIndex: number
7+
showChevron: boolean
8+
allowMouseMove: boolean
9+
isHoveringOnPresenter: boolean
10+
onClickClose: () => void
11+
}
12+
13+
export const NavigationContext = createContext<NavigationContextProps>({
14+
optionIndex: -1,
15+
showChevron: false,
16+
allowMouseMove: false,
17+
isHoveringOnPresenter: false,
18+
onClickClose: noop,
19+
})

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ export * from './components/Header'
2828
export * from './layout/GNB'
2929
export * from './layout/GlobalHeader'
3030
export * from './layout/Client'
31-
export * from './layout/HeaderContent'
3231
export * from './layout/Main'
3332
export * from './layout/Navigations'
3433

src/layout/Client/utils/LayoutReducer.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { insertItem, removeItem } from '../../../utils/utils'
2+
13
export interface NavigationState {
24
initialWidth: number
35
maxWidth: number
@@ -10,21 +12,24 @@ export interface LayoutState {
1012
sideWidth: number | null
1113
showSideView: boolean
1214
showNavigation: boolean
15+
navOptions: NavigationState[]
1316
}
1417

1518
export const defaultState: LayoutState = {
1619
sideWidth: null,
1720
showSideView: false,
1821
showNavigation: true,
22+
navOptions: [],
1923
}
2024

2125
export enum ActionType {
2226
SET_SIDE_WIDTH,
2327
OPEN_SIDE_VIEW,
2428
CLOSE_SIDE_VIEW,
2529
SET_SHOW_NAVIGATION,
26-
ADD_NAVIGATION,
27-
CLEAR_NAVIGATIONS,
30+
ADD_NAV_OPTION,
31+
REMOVE_NAV_OPTION,
32+
CLEAR_NAV_OPTION,
2833
}
2934

3035
interface SetSideWidthAction {
@@ -45,11 +50,28 @@ interface SetShowNavigationAction {
4550
payload: boolean
4651
}
4752

53+
interface AddNavOptionAction {
54+
type: ActionType.ADD_NAV_OPTION
55+
payload: { index: number, option: NavigationState }
56+
}
57+
58+
interface RemoveNavOptionAction {
59+
type: ActionType.REMOVE_NAV_OPTION
60+
payload: { index: number }
61+
}
62+
63+
interface ClearNavOptionAction {
64+
type: ActionType.CLEAR_NAV_OPTION
65+
}
66+
4867
export type LayoutAction = (
4968
SetSideWidthAction |
5069
OpenSideViewAction |
5170
CloseSideViewAction |
52-
SetShowNavigationAction
71+
SetShowNavigationAction |
72+
AddNavOptionAction |
73+
RemoveNavOptionAction |
74+
ClearNavOptionAction
5375
)
5476

5577
function LayoutReducer(state: LayoutState = defaultState, action: LayoutAction): LayoutState {
@@ -82,6 +104,27 @@ function LayoutReducer(state: LayoutState = defaultState, action: LayoutAction):
82104
}
83105
}
84106

107+
case ActionType.ADD_NAV_OPTION: {
108+
return {
109+
...state,
110+
navOptions: insertItem(state.navOptions, action.payload.index, action.payload.option),
111+
}
112+
}
113+
114+
case ActionType.REMOVE_NAV_OPTION: {
115+
return {
116+
...state,
117+
navOptions: removeItem(state.navOptions, action.payload.index),
118+
}
119+
}
120+
121+
case ActionType.CLEAR_NAV_OPTION: {
122+
return {
123+
...state,
124+
navOptions: [],
125+
}
126+
}
127+
85128
default:
86129
return state
87130
}

src/layout/HeaderArea/HeaderArea.styled.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ export const HeaderWrapper = styled.div.attrs(({ showSideView, sideWidth }: Head
1818
grid-column: 1 / 3;
1919
`
2020

21-
export const LeftHeader = styled.div`
21+
export const ContentHeader = styled.div`
2222
grid-row: 1 / 2;
2323
grid-column: 1 / 2;
2424
`
2525

26-
export const RightHeader = styled.div`
26+
export const CoverableHeader = styled.div`
2727
grid-row: 1 / 2;
2828
grid-column: 2 / 3;
2929
`

src/layout/HeaderArea/HeaderArea.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React, { forwardRef } from 'react'
33

44
/* Internal dependencies */
55
import useLayoutState from '../../hooks/useLayoutState'
6-
import { HeaderWrapper, LeftHeader, RightHeader } from './HeaderArea.styled'
6+
import { HeaderWrapper, ContentHeader, CoverableHeader } from './HeaderArea.styled'
77
import HeaderAreaProps from './HeaderArea.types'
88

99
export const HEADER_AREA_TEST_ID = 'ch-design-system-header-area'
@@ -12,7 +12,7 @@ function HeaderArea(
1212
{
1313
style,
1414
className,
15-
mainHeader,
15+
contentHeader,
1616
coverableHeader,
1717
testId = HEADER_AREA_TEST_ID,
1818
hasHeader,
@@ -34,8 +34,8 @@ function HeaderArea(
3434
showSideView={showSideView}
3535
{...otherProps}
3636
>
37-
<LeftHeader>{ mainHeader }</LeftHeader>
38-
<RightHeader>{ coverableHeader }</RightHeader>
37+
<ContentHeader>{ contentHeader }</ContentHeader>
38+
<CoverableHeader>{ coverableHeader }</CoverableHeader>
3939
</HeaderWrapper>
4040
)
4141
}

src/layout/HeaderContent/HeaderContent.tsx

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/layout/HeaderContent/HeaderContent.types.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/layout/HeaderContent/index.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/layout/Main/Main.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* External dependencies */
22
import React, { forwardRef, useCallback, useRef } from 'react'
3-
import { clamp, get, isNil } from 'lodash-es'
3+
import { clamp, isNil } from 'lodash-es'
44
import { window } from 'ssr-window'
55

66
/* Internal dependencies */
@@ -18,7 +18,8 @@ import MainProps from './Main.types'
1818
function Main(
1919
{
2020
content,
21-
header,
21+
contentHeader,
22+
coverableHeader,
2223
sidePanel,
2324
sideView,
2425
navigationRef,
@@ -34,11 +35,8 @@ function Main(
3435
const sideInitialWidth = useRef(0)
3536
const initialPosition = useRef(0)
3637

37-
const mainHeader = get(header, 'props.mainHeader', null)
38-
const coverableHeader = get(header, 'props.coverableHeader', null)
39-
4038
const hasSide = !isNil(sidePanel) || showSideView
41-
const hasHeader = !isNil(mainHeader || coverableHeader)
39+
const hasHeader = !isNil(contentHeader || coverableHeader)
4240

4341
const handleResizerMouseDown = useCallback((e: MouseEvent) => {
4442
contentInitialWidth.current = contentRef.current!.clientWidth
@@ -79,7 +77,7 @@ function Main(
7977
>
8078
<HeaderArea
8179
hasHeader={hasHeader}
82-
mainHeader={mainHeader}
80+
contentHeader={contentHeader}
8381
coverableHeader={coverableHeader}
8482
/>
8583
<ContentArea

src/layout/Navigations/NavigationArea/NavigationArea.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { noop } from 'lodash-es'
1111
import { window, document } from 'ssr-window'
1212

1313
/* Internal dependencies */
14+
import { NavigationContext, NavigationContextProps } from '../../../contexts/NavigationContext'
1415
import useLayoutDispatch from '../../../hooks/useLayoutDispatch'
1516
import useLayoutState from '../../../hooks/useLayoutState'
1617
import useThrottledCallback from '../../../hooks/useThrottledCallback'
@@ -33,8 +34,6 @@ function NavigationArea(
3334
className,
3435
testId = NAV_TEST_ID,
3536
/* cloneElement Props */
36-
hidable = false,
37-
disableResize = false,
3837
optionIndex = 0,
3938
onMouseDown = noop,
4039
onMouseMove = noop,
@@ -44,8 +43,10 @@ function NavigationArea(
4443
forwardedRef: React.Ref<HTMLDivElement>,
4544
) {
4645
const dispatch = useLayoutDispatch()
47-
const { showNavigation } = useLayoutState()
46+
const { showNavigation, navOptions } = useLayoutState()
4847

48+
const hidable = useMemo(() => navOptions[optionIndex]?.hidable || false, [navOptions, optionIndex])
49+
const disableResize = useMemo(() => navOptions[optionIndex]?.disableResize || false, [navOptions, optionIndex])
4950
const show = useMemo(() => (hidable ? showNavigation : undefined), [hidable, showNavigation])
5051

5152
const containerRef = useRef<HTMLDivElement | null>(null)
@@ -73,11 +74,7 @@ function NavigationArea(
7374
if (!allowMouseMove) return
7475
onMouseMove(event)
7576
})
76-
}, [
77-
disableResize,
78-
allowMouseMove,
79-
onMouseMove,
80-
])
77+
}, [disableResize, allowMouseMove, onMouseMove])
8178

8279
useEventHandler(resizeBarRef, 'mousedown', handleMouseDown)
8380
useEventHandler(document, 'mouseup', handleMouseUp)
@@ -121,14 +118,13 @@ function NavigationArea(
121118
}
122119
}, [handleDecideHover, show])
123120

124-
const ContentComponent = useMemo(() => (
125-
React.cloneElement(children, {
126-
showChevron,
127-
allowMouseMove,
128-
isHoveringOnPresenter,
129-
onClickClose: handleClickClose,
130-
})
131-
), [allowMouseMove, children, handleClickClose, isHoveringOnPresenter, showChevron])
121+
const navigationContextValues: NavigationContextProps = useMemo(() => ({
122+
optionIndex,
123+
showChevron,
124+
allowMouseMove,
125+
isHoveringOnPresenter,
126+
onClickClose: handleClickClose,
127+
}), [allowMouseMove, handleClickClose, isHoveringOnPresenter, optionIndex, showChevron])
132128

133129
return (
134130
<NavigationContainer
@@ -147,7 +143,9 @@ function NavigationArea(
147143
onMouseEnter={handlePresenterMouseEnter}
148144
onMouseLeave={handlePresenterMouseLeave}
149145
>
150-
{ ContentComponent }
146+
<NavigationContext.Provider value={navigationContextValues}>
147+
{ children }
148+
</NavigationContext.Provider>
151149
</NavigationPresenter>
152150
</NavigationPositioner>
153151
<ResizeBar

src/layout/Navigations/NavigationContent/NavigationContent.tsx

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
/* External dependencies */
2-
import React, { useMemo } from 'react'
3-
import { noop } from 'lodash-es'
2+
import React, { useContext, useLayoutEffect, useMemo } from 'react'
3+
import { isNil } from 'lodash-es'
44

55
/* Internal dependencies */
66
import { mergeClassNames } from '../../../utils/stringUtils'
7+
import { NavigationContext } from '../../../contexts/NavigationContext'
8+
import { ActionType } from '../../Client/utils/LayoutReducer'
9+
import useLayoutDispatch from '../../../hooks/useLayoutDispatch'
710
import {
811
ChevronIcon,
912
StyledContentWrapper,
@@ -28,14 +31,40 @@ function NavigationContent({
2831
onScroll,
2932
children,
3033

31-
/* Navigations Injected Props */
32-
showChevron = false,
33-
allowMouseMove = false,
34-
isHoveringOnPresenter = false,
35-
onClickClose = noop,
36-
optionIndex,
34+
/* LayoutState Prop */
35+
layoutOption,
36+
showNavigation,
3737
...otherProps
3838
}: NavigationContentProps) {
39+
const {
40+
optionIndex,
41+
showChevron,
42+
allowMouseMove,
43+
isHoveringOnPresenter,
44+
onClickClose,
45+
} = useContext(NavigationContext)
46+
47+
const dispatch = useLayoutDispatch()
48+
49+
// NOTE: LAYOUTEFFECT를 사용하지 않으면 initial 값이 없을때 순간 깜빡임이 발생한다
50+
useLayoutEffect(() => {
51+
if (optionIndex === 0) {
52+
dispatch({ type: ActionType.CLEAR_NAV_OPTION })
53+
}
54+
55+
dispatch({
56+
type: ActionType.ADD_NAV_OPTION,
57+
payload: { index: optionIndex, option: layoutOption },
58+
})
59+
60+
if (!isNil(showNavigation)) {
61+
dispatch({
62+
type: ActionType.SET_SHOW_NAVIGATION,
63+
payload: showNavigation,
64+
})
65+
}
66+
}, [dispatch, layoutOption, optionIndex, showNavigation])
67+
3968
const clazzName = useMemo(() => (
4069
mergeClassNames(className, ((withScroll && scrollClassName) || undefined))
4170
), [className, scrollClassName, withScroll])

0 commit comments

Comments
 (0)