이번 단계에서는 context를 추가하여 상태 관리를 했을 때
최적화가 풀리는 문제 해결해보자.
⚠️ 최적화가 풀리는 원인
프로바이더 컴포넌트도 엄연히 리액트 컴포넌트이다.
그래서 todos 값이 변경되면 해당하는 컴포넌트도
리렌더링되는데, 그 과정에서 프로바이더에게 전달하는
value 안의 객체가 다시 만들어지기 때문이다.


그렇다면 이 문제는 어떻게 해결할 수 있을까?
TodoContext를 두 개로 분리하여 해결 할 수 있다.
state로 값이 변경되는 요소와 호출만 되어따로 값이 변경되지 않는 함수는 분리해주는 것이다.

1. 분리된 Context 만들기
기존에 만들어 둔 컨텍스트를 삭제하고
값이 변하는 컨텍스트와 변하지 않는 컨텍스트 두 개로 나누어
각각의 컨텍스트를 새로 만들어주자.
// export const TodoContext = createContext();
export const TodoStateContext = createContext();
export const TodoDispatchContext = createContext();그리고 상위에
TodoStateContext.Provider컴포넌트로 감싸고전달해줄 데이터인
todos를 value값으로 넣어주자.하나의 값만 존재하기 때문에 객체가 아닌 일반변수로 넣어주자.
그리고
TodoDispatchContext.Provider에는 value값으로아까와 같은 객체 형태에서
todos만 뺀 나머지 값들을넣을 수 있다.
<div className="App">
<Header />
<TodoStateContext.Provider value={todos}>
<TodoDispatchContext.Provider value={{onCreate, onUpdate, onDelete}}>
<Editor />
<List />
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
</div>;하지만 이렇게만 하면 상위에 있는
todos 값이 변경되며어짜피
{onCreate, onUpdate, onDelete} 이 객체 자체가다시 만들어지는 문제는 해결되지 않는다.
2. 변경되지 않는 함수 메모이제이션하기
따라서 우리는 이 객체를 메모이제이션 기법으로 재생성되지
않게 변경해줄 것이다.
useMemo훅을 추가하고 memoizedDispatch에 useMemo를호출하여 첫 번째 인수로 콜백 함수 내에 재생성되지 않고자 하는
객체를 그대로 반환하게 넣어주자.
그리고 두 번째 인수인 deps자리에 빈 배열을 두어 이 객체가
마운트 될 때만 렌더링 되도록 만들어주자.
const memoizedDispatch = useMemo(() => {
return { onCreate, onUpdate, onDelete };
}, []);다음으로 메모이제이션된 이 객체를 그대로
프로바이더 컴포넌트의
value에 넣어주자.<TodoDispatchContext.Provider value={memoizedDispatch}>
<Editor />
<List />
</TodoDispatchContext.Provider>;3. 변경된 프로바이더 이름으로 공급받기
이제는 각각의 컴포넌트에서 변경된 이름의 컨텍스트로
필요한 값을 꺼내주도록 하자.
먼저
Editor컴포넌트에서는 다음과 같이 이름이 변경될 것이다.const { onCreate } = useContext(TodoDispatchContext);마찬가지로
TodoITem컴포넌트에서도 변경된 컨텍스트의이름으로 값을 공급받자.
const { onUpdate, onDelete } = useContext(TodoDispatchContext);List컴포넌트에서는 객체 형태로 넘기지 않았기 때문에더 이상 구조분해할당으로 값을 받지 않고 일반 변수인
todos로 값을 받아주자.
const todos = useContext(TodoStateContext);Share article