-
[React]How to optimize context value (번역)JavaScript 2022. 3. 3. 22:14
원글: https://kentcdodds.com/blog/how-to-optimize-your-context-value — Kent C. Dodds
주의: 시작하기 전 알아둘것. 아래 조건에 해당하는 사항이 여러 개 있는 경우 컨텍스트 값 최적화를 효과적으로 도입 할 수 있습니다.
1. 컨텍스트 값이 자주 바뀔 경우
2. 컨텍스트 값을 사용하는 소비자 컴포넌트가 많을 경우
3. `React.memo` 의 느린 성능에 지친 경우
4. 당신이 프로그램을 실행 했을때 느리다고 생각하여, 최적화가 필요한 경우만약 위 설명 중 해당사항이 있으면, 계속 읽으세요 (끝까지 읽고 더 나은 대안을 놓치지 마세요!).
정말로 대안은 확실히 좋을 겁니다. 심지어 나는 원래 작성했던 블로그 포스트를 삭제하고 다른 더 나은 방법을 알려주기 위해 이 게시물을 다시 작성했습니다. 기존에 작성했던 포스트는 여기서
진지하게, 만약 당신 코드가 느리다고 생각해서 이짓을 하려고 하는 거면 굳이 안해도 되요. 사실 리액트는 정말 빠르고, 성능이 충분할 때 성능이라는 명목하에 복잡성을 늘리는건 오히려 복잡성을 늘릴 뿐이니깐요.컨텍스트 값을 최적화 할 수 있는 가장 심플한 방법은 상태 관리를 위해
useReducer
혹은useState
를 사용하는 것이에요. 그리고state
를 하나의 특정 함수에 넣고dispatch
를 다른 함수에 넣으세요. ( 아래 코드의 예시에서 state 는 useCountState 에서, dispatch 는 useCountUpdater 에서 불러옵니다.)import React from 'react' import ReactDOM from 'react-dom' import {CountProvider, useCountState, useCountUpdater} from './count-context' function useRenderCounter() { const ref = React.useRef() React.useEffect(() => { ref.current.textContent = Number(ref.current.textContent || '0') + 1 }) return ( <span style={{ backgroundColor: '#ccc', borderRadius: 4, padding: '2px 4px', fontSize: '0.8rem', margin: '0 6px', display: 'inline-block', }} ref={ref} /> ) } const CountDisplay = React.memo(function CountDisplay() { const count = useCountState() const renderCount = useRenderCounter() return ( <div style={{border: '1px solid black', padding: 10}}> {renderCount} {`The current count is ${count}. `} </div> ) }) const Counter = React.memo(function Counter() { const increment = useCountUpdater() const renderCount = useRenderCounter() return ( <div style={{border: '1px solid black', padding: 10}}> {renderCount} <button onClick={increment}>Increment count</button> </div> ) }) function App() { const [, forceUpdate] = React.useState() const renderCount = useRenderCounter() return ( <div style={{border: '1px solid black', padding: 10}}> {renderCount} <button onClick={() => forceUpdate({})}>force render</button> <CountProvider> <CountDisplay /> <Counter /> </CountProvider> </div> ) } ReactDOM.render(<App />, document.getElementById('root'))
사실 위 경우에는
useMemo
를 사용할 필요가 없고, 단지 업데이터 컨텍스트(useCountUpdater) 만을 사용해서 리랜더링을 방지 할 수 있습니다.<Counter />
컴포넌트의 컨텍스트가 업데이트 되지 않아서 해당 컴포넌트의 리랜더링을 막을 수 있다는 것을 제외하곤, 이 방법은 기존의useMemo
를 활용한 해결책과 같습니다. (Counter 컴포넌트에서 useCountState 를 통해 context value 를 구독하고 있지 않기 때문에 dispatch 가 발생해 useCountState 의 value 가 변해도 Counter 컴포넌트는 리랜더링 되지 않습니다.)저는 개인적으로 이 방법이 대부분의 상황에 있어서 오히려 더 복잡하게 만든다고 생각하기 때문에 모든 상황에서 굳이 이 방법을 고수하진 않을겁니다. 하지만, 만약에 위에서 언급한 모든 문제를 가지고 있으면 이 방법을 도입해 해결해보는것도 좋은 시도일겁니다.
State 와 dispatch 를 분리하는 건 귀찮다.
몇몇 사람들은 State 와 dispatch 로 분리하는 것은 귀찮은 과정이라고 생각합니다.
const state = useCountState() const dispatch = useCountDispatch()
그들은 그냥 이렇게 하면 안돼? 라고 묻습니다.
const [state, dispatch] = useCount()
물론 그렇게 해도 됩니다!!
function useCount() { return [useCountState(), useCountDispatch()] }
하지만 기억해두세요. 이러한 구조를 사용할 때, state 와 dispatch 둘 중 하나만 필요할 경우 성능상 이점을 잃게될 수 있습니다.
그리고 리액트 컨텍스트를 효과적으로 사용하는 방법 도 꼭 읽어보세요.
'JavaScript' 카테고리의 다른 글
[번역]리액트를 언제 써야되는가? (0) 2022.04.13 자바스크립트에서 함수와 메서드의 차이점 (0) 2022.03.05 [react] Fragments (0) 2022.03.02 [react] forwardRef (0) 2022.03.02 [개발일지] 2.8 에러메세지는 구체적으로 콘솔에 띄우기 (0) 2022.02.08