Apollo Client에서 local state 관리
단순히
makrVar()
로만 선언한 reactive variable
의 값의 변화는 컴포넌트를 리렌더링 시키지 않는다. useReactiveVar()
로 감싸야 reactive variable의 값을 컴포넌트의 state로 다이렉트로 사용하게 되며, 이 경우에는 reactive variable의 값이 바뀐다면 컴포넌트의 state가 바뀐 것이므로 컴포넌트도 리렌더링 된다.apollo global state의 문제점
리액트 상태관리 라이브러리 역사와 Recoil 에서 Context API의 단점을 설명하는 부분을 참고하자.
apollo의 global state는 Context API의 단점과 완전히 동일한 이슈가 있다.
상태의 일부만 바뀌었더라도 전체가 바뀌었다고 인지하여 해당 상태를 구독하고 있는 모든 컴포넌트가 리렌더링 된다.
( 비록 해당 컴포넌트가 참조하는 값은 이전과 동일함에도 불구하고! )
// ---- global state 선언 ------------------------------- const apolloState = makeVar({ id: 0, name: 'n' }); // ---- getter ----------------------------------------- // makeVar의 getter()를 직접 참조하는 경우에는 값이 바뀌더라도 컴포넌트를 리렌더링을 일으키지 않음. const useGetId = () => { const {id} = apolloState(); return id; } // useReactiveVar로 감쌌으므로 값이 바뀌면 컴포넌트도 리렌더링 된다. // id 값만 반환하므로 name이 바뀔 때는 리렌더링이 되지 않았으면 하지만, 실제로는 name이 바뀌어도 리렌더링 된다. const useGetReactiveId = () => { const {id} = useReactiveVar(apolloState); return id; }
영상의 빨간 부분은
id
값만 변경시키고, 초록 부분은 name
값만 변경시키는 예시다.{ id: number, name: string }
형태의 상태를 선언하였다.Profiler로 보면 id 값만 바꿀 때도 name 값만 사용하는 컴포넌트도 같이 리렌더링되고, 반대의 경우도 마찬가지임을 알 수 있다.
즉,
Context API
와 마찬가지의 해결책으로 두 개의 값의 변화에 독립적으로 관리하고 싶다면, reactiveVar를 각각 별도로 선언하여 사용하여야 한다.해결방안
- 각각 독립적으로
makeVar()
를 선언하여 사용한다.
redux
에서는shallowEqual
이라는 옵션을 주어서 해결할 수 있었다.- apollo client에는 shallowEqual과 같은 옵션이 없다.
atom
기반의 상태관리 라이브러리를 쓰자 ← 추천!recoil
← 추천!jotai