요즘 핫한 Recoil를 시작하기에 앞서 알아보자 !

나의 첫 velog 게시물을 그동안 공부하고 싶었던 Recoil 로 시작하려 한다 😀


지난 5개월간 회사에서 React를 사용한 2개의 웹과 React-Native를 사용 2개의 앱 프로젝트를 진행하며 상태관리에 대해 좀 더 진지하게 생각한 계기가 된것 같다.

위 프로젝트에서 사용한 전역상태관리 라이브러리 및 API 는
Context API, Redux, Redux-saga 를 주로 써왔는데

사실 ...
Context API 는 뷰포트를 활용한 반응형 웹 구축과 테마를 주로 변경할때 썼고
이 외의 전역 상태관리는 Redux와 Redux-saga 조합을 사용해왔는데
구현하는 기능에 비해 헤비하다는 느낌이 컸었다
(전역적 상태관리 외 미들웨어를 사용할 일이 크게 없었음...)

그래서 좀 더 라이트하면서 리액트 스럽고, 직관적인 코드를 사용하는 라이브러리가 무엇이 있을까하다가 Recoil 을 발견했다..!
(아직 안정성에 있어서 이슈가 있다고는 하지만... 전 페이스북을 믿습니다😀)





💡 Recoil 이란? 'React를 위한 상태관리 라이브러리' 이다. 

1. Recoil의 등장 동기

'우리는 API와 의미 및 동작을 가능한 React답게 유지하면서 React의 상태관리와 관련된 한계점을 개선하고자 한다.'

출처: Recoil 공식 홈페이지

React 상태관리의 한계점


  • 상태를 최상단까지 끌어올릴 수 있지만 컴포넌트 트리 자체의 리렌더링을 야기
  • 내장된 Context API 기능은 단일 값만 저장할 수 있다.
  • 위 두가지 특성이 트리의 최상단(state가 존재하는 곳) 부터 최하위(state가 사용되는 곳) 까지의 코드 분할을 어렵게 한다.

Recoil 을 통한 상태변화 접근 방식


💡 Recoil의 상태 변화는 그래프의 뿌리 (atoms 이라고 부름) 로부터 순수함수(selectors라고 부름) 를 거쳐 컴포넌트로 흐르게 된다. * atoms(공유상태) ⇒ selectors(순수 함수) ⇒ component(View)
  • 공유상태(shared state) 도 React 의 내부 상태(useState?) 처럼 간단한 get/set 인터페이스로 사용할 수 있도록 boilerPlate-free API 제공 ( 필요에 따라 reducers 등으로 캡슐화 가능)
  • 동시성 모드(Concurrent Mode)를 비롯한 다른 새로운 React의 기능들과 호환 가능성도 갖는다.
  • 상태 정의는 코드 분할이 가능하다.
  • 상태를 사용하는 컴포넌트를 수정하지 않고도 상태를 파생된 데이터로 대체할 수 있다.
  • 파생된 데이터를 사용하는 컴포넌트를 수정하지 않고도 파생된 데이터는 동기식과 비동기식 간에 이동할 수 있다.
  • 우리는 탐색을 일급 개념으로 취급할 수 있고 심지어 링크에서 상태 전환을 인코딩할 수도 있다.
  • 역호환성 방식으로 전체 애플리케이션 상태를 유지하는 것은 쉬우므로, 유지된 상태는 애플리케이션 변경에도 살아남을 수 있다.

2. Recoil 의 주요 개념

개요


💡 recoil을 통해 atoms(공유상태) 에서 selectors(순수 함수)를 거쳐 Component 로 내려가는 data-flow-graph 를 만들 수 있다.

atoms는 컴포넌트가 구독할 수 있는 상태의 단위이고
selectors는 atoms의 상태값을 동기 또는 비동기 방식을 통해 변환할 수 있다.

Atoms


💡 Atoms는 상태의 단위이며, 업데이트와 구독이 가능하다. Atoms가 업데이트 되면 각 구독하는 컴포넌트들은 새로운 값을 반영하여 리 렌더링 된다. 동일한 atom이 여러 컴포넌트에서 사용되는 경우 모든 컴포넌트는 상태를 공유한다.
  1. Atoms 기본 생김새 (공식 홈페이지 예제 활용)
const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});

⭐️ Atoms는 디버깅, 지속성 및 모든 atoms의 map을 볼 수 있는 고유한 키 (unique key) 가 필요하다.
주의점: 고유한 키 이기에 두 개의 atom이 같은 키를 가질 수 없으며, 키 값는 전역적으로 고유해야한다.

  1. 컴포넌트에서 atom을 읽고 쓰는 방법: useRecoilState 라는 Hook을 사용한다.
function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return (
    <button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
      Click to Enlarge
    </button>
  );
}

😍 위 useRecoilState를 보고 느낀점은... useState Hook 과 사용방법이 똑같다 !!! 아주 나이스 ~~

버튼을 클릭하면 버튼의 글꼴 크기가 1만큼 증가하며,
해당 atom(fontSizeState)을 사용하는 다른 컴포넌트의 글꼴 크기도 같이 변화 한다.

function Text() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return <p style={{fontSize}}>This text will increase in size too.</p>;
}

Selectors


💡 Selectorssms atoms나 다른 selectors를 받아 데이터를 가공하여 리턴하는 순수 함수(pure function)이다. 상위의 atoms 또는 selectors가 업데이트 되면 하위의 selector 함수도 다시 실행 된다. 모든 컴포넌트 들은 selectors를 atoms처럼 구독할 수 있고, seletors가 변경되면 구독중인 컴포넌트들도 리렌더링 된다.

Selectors는 상태를 기반으로 하는 파생 데이터를 계산하는 데 사용된다.
최소한의 상태 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는
selectors에 명시한 함수를 통해 효율적으로 계산함으로서 쓸모없는 상태의 보존을 방지한다.

Selectors는 자신을 구독한 컴포넌트, 그리고 의존하는 상태의 값을 추적한다.

  1. Selectors 의 내부 생김새
function selector<T>({
  key: string,

  get: ({
    get: GetRecoilValue
  }) => T | Promise<T> | RecoilValue<T>,

  set?: (
    {
      get: GetRecoilValue,
      set: SetRecoilState,
      reset: ResetRecoilState,
    },
    newValue: T | DefaultValue,
  ) => void,

  dangerouslyAllowMutability?: boolean,
})

⭐️get 속성은 계산될 함수(데이터가 가공되는 로직)이며 전달되는 get 인자를 통해 atoms나 다른 selectors에 접근 가능하다.

 다른 atoms 나 selectors 에 접근하면 자동으로 종속관계가 형성되고 의존된다. 

get은 default로 제공되는 함수이고, option으로 제공되는 set을 쓰고 싶다면 공식 홈페이지에 나와있는 set 속성의 예제를 함께 참고 !

const proxySelector = selector({
  key: 'ProxySelector',
  get: ({get}) => ({...get(myAtom), extraField: 'hi'}),
  set: ({set}, newValue) => set(myAtom, newValue),
});
const transformSelector = selector({
  key: 'TransformSelector',
  get: ({get}) => get(myAtom) * 100,
  set: ({set}, newValue) =>
    set(myAtom, newValue instanceof DefaultValue ? newValue : newValue / 100),
});

이 외 selector 함수 내에서 동기 또는 비동기 식으로 api를 요청할 수도 있고, 단수 또는 복수의 atom의 값을 바꾸고 가공, 그리고 더 나아가 캐싱과 loadable 과 같은 일들도 처리할 수 있는데 추후 학습해나가보기로 한다 !

처음 접한 recoil이지만 react를 사용하는 개발자라면 금방 실무에 적용할 수 있을 것 같은 느낌이였다 !

이 외 에도

Recoil 공식 홈페이지에서 많은 기능들과 레퍼런스 API 를 확인할 수 있다.

등장배경부터 주요 개념까지 살펴본 Recoil이지만... redux의 늪에서 빠져나올 생각하니 벌써 설레는것 무엇..

Reference


Recoil 공식 홈페이지

좋은 웹페이지 즐겨찾기