Recoil을 사용해보자

date
Sep 8, 2022
thumbnail
slug
Recoil을 사용해보자
author
status
Published
tags
Library
React
summary
기존에 자주 사용하는 Redux는 사용자의 명령(action)을 Reducer->Store로 전달하여 상태를 변화시키고 그 값을 Component에 반영하는 원리인데 나는 React-Redux를 사용하면서 React에서 쓰는게 좀 어색한데?/React스럽지 않은데?라고 생각했다.
type
Post
updatedAt
Jan 22, 2023 01:19 AM
notion image
기존에 자주 사용하는 Redux는 사용자의 명령(action)을 Reducer->Store로 전달하여 상태를 변화시키고 그 값을 Component에 반영하는 원리인데 나는 React-Redux를 사용하면서 React에서 쓰는게 좀 어색한데?/React스럽지 않은데?라고 생각했다.
React는 hook을 사용하면서 컴포넌트에서 useState로 상태를 직접 변경하는데"상태관리를 기존의 useState와 비슷하게 할 수는 없을까."라는 의문이 들었고 토스에서 사용하는 상태관리 라이브러리인 Recoil을 찾았다.

1. 이거다..!


Recoil 공식문서를 보면 제작자의 동기가 나와있는데
우리는 API와 의미 및 동작을 가능한 React답게 유지하면서 이것을 개선하고자 한다.
Recoil의 상태변화는 atom으로부터 selector를 통해 컴포넌트로 이동하는 방식이다.atom은 컴포넌트가 Subscribe할 수 있는 상태의 단위이며 Selector는 atom상태값을 동기/비동기방식으로 변환한다.

2. Atoms


Redux와 달리 Recoil은 Atom으로 상태를 관리한다.
Atom이 업데이트 되면 atom을 구독한 컴포넌트는 새로운 값을 받아 재렌더링된다.
atom은 다음과 같이 사용한다.
const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});
Atom은 고유한 키가 필요한데 이 키는 전역적으로 고유해야하며 Component가 atom을 구독할 때 사용된다.
위 예시처럼 기본값도 가진다.useState와 매우 유사하다.
컴포넌트에서 atom을 사용하려면 useRecoilState라는 Hook을 사용한다.간단하게 말해 전역으로 사용할 수 있는useState이다.
function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return (
    <button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
      Click to Enlarge
    </button>
  );
}
버튼을 누르면 글꼴의 크기가 1증가하며 fontSizeState를 사용하는 다른 컴포넌트의 글꼴도 같이 변화한다.

3. Selectors


Selector는 atom이나 다른 selector를 입력으로 받는 함수이다.
상위 atom, selector가 업데이트되면 하위 selector도 재실행된다.컴포넌트들은 selectors를 구독할 수 있고 selector가 변경되면 컴포넌트도 재렌더링된다.
Selectors는 상태를 기반으로 하는 파생 데이터를 계산하는 데 사용된다. 최소한의 상태만 atoms에 저장하고 다른 모든 데이터는 selectors에 명시한 함수를 통해 효율적으로 계산함으로써 쓸모없는 상태의 보존을 방지한다.
const fontSizeLabelState = selector({
  key: 'fontSizeLabelState',
  get: ({get}) => {
    const fontSize = get(fontSizeState);
    const unit = 'px';

    return `${fontSize}${unit}`;
  },
});
전달되는 get 인자를 통해 atoms와 다른 selectors에 접근할 수 있다.참조했던 다른 atoms나 selectors가 업데이트되면 이 함수도 다시 실행된다.
위 예시에서 selector는 fontSizeState라는 하나의 atom에 의존성을 갖는다.
function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  const fontSizeLabel = useRecoilValue(fontSizeLabelState);

  return (
    <>
      <div>Current font size: ${fontSizeLabel}</div>

      <button onClick={setFontSize(fontSize + 1)} style={{fontSize}}>
        Click to Enlarge
      </button>
    </>
  );
}
Selector는 useRecoilValue를 통해 읽을 수 있다.

Redux보다 Recoil을 보니 선녀같다.