반디북
리액트 훅을 활용한 마이크로 상태 관리
Ch10
준영

사용 사례 시나리오 4: React Tracked

React Tracked의 특징은 다음과 같다.

  • 속성 감지를 기반 상태 사용 추적 라이브러리
  • Valtio와 동일하게 Proxy 사용으로 리렌더링 최적화

추가적으로 리액트 뿐만 아니라 Redux, Zustand 등 다른 라이브러리와 함께 사용이 가능하다.

React Tracked 이해하기

React Tracked는 상태 관리 기능을 제공하지는 않는다.
하지만 상태 사용 추적을 통한 리렌더링 최적화 기능을 제공한다.

다시 React Context에 대해 상기 시켜보자.

  • 컴포넌트 트리의 서브 트리를 Provider로 묶어 각 서브 트리에서 다른 컨텍스트를 사용할 수 있다.
  • 컨텍스트의 속성 중 하나가 변경되더라도 Provider 내의 해당 컨텍스트를 사용하는 모든 컴포넌트에서 리렌더링이 발생한다.

먼저, 컨텍스트를 활용하여 작성한 코드를 살펴보자.

const useValue = () => useState({ count: 0, text: 'hello' });
 
const StateContext = createContext(useValue);
 
const useStateContext = () => {
  const contextValue = useContext(StateContext);
  if (contextValue === null) {
    throw new Error('Please use Provider');
  }
  return contextValue;
};
 
const Counter = () => {
  const [state, setState] = useStateContext();
  const inc = () => {
    setState((prev) => ({
      ...prev,
      count: prev.count + 1,
    }));
  };
 
  return (
    <div>
      count: {state.count}
      <button onClick={inc}>+1</button>
    </div>
  );
};

위 경우, 컨텍스트에 등록된 값중, count만을 사용하고 있지만, text만 변경되어도 컨텍스트의 변경이 감지되어 컨텍스트를 사용중인 모든 컴포넌트에서 리렌더링이 발생한다는 문제가 발생한다.

React Tracked는 Provider와 useTracked 훅을 제공한다.
Provider는 컨텍스트에서 사용하는 Provider와 동일한 역할을 수행한다.
useTracked는 useContext 대신 사용이 가능한 훅으로 Provider 내에 저장된 컨텍스트를 추적한다.
따라서 해당 속성의 변경을 감지하고 컨텍스트를 사용하는 모든 컴포넌트가 아닌, 해당 속성만을 사용하고 있는 컴포넌트를 추적하여 리렌더링한다. 이렇게 useTracked 훅으로 어떤 상태가 사용되었는지를 감지하는 상태 추적 기능을 통해 리렌더링을 최적화한다.

import { createContainer } from 'react-tracked';
 
const useValue = () => useState({ count: 0, text: 'hello' });
 
const { Provider, useTracked } = createContainer(useValue);
 
const Counter = () => {
  const [state, setState] = useTracked();
  const inc = () => {
    setState((prev) => ({ ...prev, count: prev.count + 1 }));
  };
 
  return (
    <div>
      count: {state.count}
      <button onClick={inc}>+1</button>
    </div>
  );
};

React Tracked는 컨텍스트를 사용하지 않는 경우를 위해서 createTrackedSelector라는 저수준 함수를 제공한다.
createTrackedSelector 함수는 선택자 함수를 파라미터로 받아, useTrackedState 라는 훅을 반환한다.
useTrackedState 훅은 상태 사용 추적을 위해 전체 상태를 Proxy로 감싸 반환한다.
이를 통해 컨텍스트를 사용하지 않더라도 Redux와 같은 라이브러리와 함께 상태 추적 기능을 활용하여 리렌더링을 최적화할 수 있다.

향후 전망

React Tracked는 두 내부 라이브러리에 의존한다.

  • proxy-compare
  • use-context-selector

React Tracked는 두 가지 경우에 따라 사용법이 다르다.

  • 컨텍스트를 사용한다면, createContainer
  • 사용하지 않는다면, createTrackedSelector

React Tracked에서 컨텍스트를 사용할 경우, use-context-selector가 중요하다.
리액트 컨텍스트 값이 변경되었을때, 모든 컴포넌트가 리렌더링되는 방식을 개선하는데 도움을 주기 때문이다.
이 useContextSelector 훅은 향후 리액트에서 등장할 가능성이 있다고 하는데, 근 3년간 업데이트가 없는 것 같다.
만약 지원되었다면 호환성이 좋아 많이 사용되지 않았을까 싶다.

도은
  • React Tracked속성 감지를 기반으로 자동으로 렌더링 최적화 수행
  • 불필요한 리렌더링 제거 기능을 제공

React Tracked 이해하기

  • 상태 관리 기능 제공 X, 렌더링 최적화 기능 제공 O
  • useContext 대신 useTracked를 사용해보자
    • 상태를 Proxy로 감싸서 사용을 추적
    • Valtio와 동일하게 사용 추적 기능

향후 전망

  • React Tracked는 두 개의 내부 라이브러리에 의존
    • proxy-compare
    • use-context-selector
  • React 자체에서 유사항 형태로 구현체가 등장할 가능성이 있다.