반응형
컨텍스트 API는 props drilling을 막기 위한 수단일 뿐이며,
내부의 state가 갱신되면, 하위 컴포넌트들이 전부 렌더링되는, 리액트 컴포넌트의 룰을 벗어나지 않는다.
즉, <CountProvider />가 다시 렌더링될 때마다 하위 컴포넌트는 전부 렌더링된다.
const CountContext = React.createContext()
function CountProvider(props) {
const [count, setCount] = React.useState(0)
const value = [count, setCount]
return <CountContext.Provider value={value} {...props} />
}
언제 zustand/redux를 사용하고 언제 context API를 사용할까?
해결방법 1: contextProvider내에서 state 메모하기.
난 진정한 해결방법이라 생각하지 않는다.
상단 컴포넌트의 useMemo는 하위 컴포넌트가 memo를 사용했을 때만 효과가 있다.
useCallback도 마찬가지다.
이를 useMemo의 전파라 부를 수 있겠다.
const CountContext = React.createContext()
function CountProvider(props) {
const [count, setCount] = React.useState(0)
const value = React.useMemo(() => [count, setCount], [count])
return <CountContext.Provider value={value} {...props} />
}
function AppProvider({children}) {
const [state, dispatch] = React.useReducer(appReducer, {
dogName: '',
grid: initialGrid,
})
const value = React.useMemo(() => [state, dispatch], [state])
return (
<AppStateContext.Provider value={value}>
{children}
</AppStateContext.Provider>
)
}
useMemo 사용 이유는 1. 스테이블한 값 제공. 2. 비싼 연산 결과 저장
또한 위 방법은, state가 변경되면 아무 의미가 없다.
해결방법 2 : Dispatch provider와 Dispatch consumer 분리
dispatch만 원하는 컴포넌트에서는 dispatch만 사용하여, state 변경시 리렌더링 영향을 막자.
(당연히 메모는 해줘야 한다.)
중간의 Grid 컴포넌트는 디바운스 설정, 디스패치 함수만 넘겨주는 컴포넌트이기 때문에, 리렌더링 할 필요가 없다.
useAppDispatch를 사용하는 컴포넌트들은, state가 불변이므로 컨텍스트 값에 영향받지 않는다.
(물론 상단 컴포넌트 리렌더링의 영향은 받기 때문에 메모해줘야 한다.)
useAppState를 사용하는 컴포넌트들은 상태 변경 시 리렌더링된다.
function AppProvider({children}) {
const [state, dispatch] = React.useReducer(appReducer, {
dogName: '',
grid: initialGrid,
})
return (
<AppStateContext.Provider value={state}>
<AppDispatchContext.Provider value={dispatch}>
{children}
</AppDispatchContext.Provider>
</AppStateContext.Provider>
)
}
function useAppState() {
const context = React.useContext(AppStateContext)
if (!context) {
throw new Error('useAppState must be used within the AppProvider')
}
return context
}
function useAppDispatch() {
const context = React.useContext(AppDispatchContext)
if (!context) {
throw new Error('useAppDispatch must be used within the AppProvider')
}
return context
}
여기서 좀 더 최적화하는 방법은 https://itchallenger.tistory.com/552 참고
반응형
'FrontEnd' 카테고리의 다른 글
리액트 성능 최적화 : Production Monitoring (0) | 2022.06.05 |
---|---|
리액트 성능 최적화 : Virtual DOM (0) | 2022.06.05 |
리액트 성능 최적화 : react-virtual (0) | 2022.06.05 |
리액트 성능 최적화 : React.memo (0) | 2022.06.05 |
리액트 성능 최적화 : React.useMemo (0) | 2022.06.04 |