[React] Recoil

rik963·2022년 6월 16일
0

React

목록 보기
8/9

Recoil은 react를 위한 상태관리 라이브러리(state management library)이다.

기존의 react 상태관리 기능은 다음과 같은 한계를 가지고 있었고, 이것을 개선하고자 Recoil이 개발되었다.

React 내부 상태 관리 기능의 한계점

  1. 컴포넌트의 상태는 공통된 상위요소까지 끌어올림으로써 공유될 수 있지만, 이 과정에서 거대한 트리가 다시 렌더링되는 효과를 야기하기도 한다.
  2. Context는 단일 값만 저장할 수 있으며, 자체 소비자(consumer)를 가지는 여러 값들의 집합을 담을 수는 없다.
  3. 이 두가지 특성이 트리의 최상단(state가 존재하는 곳)부터 트리의 잎(state가 사용되는 곳)까지의 코드 분할을 어렵게한다.

Recoil이 이 문제점들을 어떻게 해결하는지 알아보자.

먼저 react 내부 상태 관리 기능을 사용한다면 아래와 같은 거대한 트리가 형성되어 앞서 언급한 문제들을 야기한다.

Recoil은 어떤 컴포넌트에서나 접근 가능한 state(global state)인 atom을 도입해서 이 문제들을 해결한다.

Recoil 설치

Recoil은 아래 명령어로 설치할 수 있다.

npm install recoil

또는

yarn add recoil

RecoilRoot

컴포넌트 내에서 recoil state를 사용하기 위해서는 부모 트리 어딘가에 RecoilRoot 컴포넌트를 넣어줘야 한다.

import React from 'react';
import ReactDOM from "react-dom/client";
import App from "./App";
import { RecoilRoot } from 'recoil';

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

root.render(
  <RecoilRoot>
      <App />
  </RecoilRoot>
);

Atom

Atom은 상태(state)의 일부를 나타낸다. Atoms는 어떤 컴포넌트에서나 읽고 쓸 수 있다. Atom의 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독(subscribe)한다. 그래서 atom에 어떤 변화가 있으면 그 atom을 구독하는 모든 컴포넌트들이 재렌더링 되는 결과가 발생할 것이다.

import { atom } from 'recoil';

export enum Categories {
  TO_DO = "TO_DO",
  DOING = "DOING",
  DONE = "DONE",
}

export const categoryState = atom<Categories>({
  key: "category", // unique ID (with respect to other atoms/selectors)
  default: Categories.TO_DO, // default value (aka initial value)
});

useRecoilState

컴포넌트가 atom을 읽고 쓰게 하기 위해서는 useRecoilState()를 아래와 같이 사용하면 된다.

import { useRecoilState } from 'recoil';

export function App() {
  return (
  	<>
      <ToDoList />
      <Search />
    </>
  );
};

function ToDoList() {
  const [category, setCategory] = useRecoilState(categoryState);
  const onInput = (event) => {
    setCategory(event.currentTarget.value);
  };
  return (
     <select value={category} onInput={onInput}>
       <option value={Categories.TO_DO}>To Do</option>
       <option value={Categories.Doing}>Doing</option>
       <option value={Categories.Done}>Done</option>
     </select>
  )
};

Selector

Selector는 파생된 상태(derived state)의 일부를 나타낸다. 파생된 상태는 상태의 변화다. 파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다.

import { selector } from 'recoil';

export const toDoSelector = selector({
  key: "toDoSelector",
  get: ({ get }) => {
    const toDos = get(toDoState);
    const category = get(categoryState);
    return toDos.filter((toDo) => toDo.category === category);
  },
});

useRecoilValue

useRecoilValue() 훅을 사용해서 selector의 값을 읽을 수 있다.

import { useRecoilState, useRecoilValue } from 'recoil';

function ToDoList() {
  const toDos = useRecoilValue(toDoSelector);
  const [category, setCategory] = useRecoilState(categoryState);
  const onInput = (event) => {
    setCategory(event.currentTarget.value);
  };
  return (
  	<>
       <select value={category} onInput={onInput}>
         <option value={Categories.TO_DO}>To Do</option>
         <option value={Categories.Doing}>Doing</option>
         <option value={Categories.Done}>Done</option>
       </select>
       <ul>
          {toDos.map((toDo) => (
            <ToDo key={toDo.id} {...toDo} />
          ))}
       </ul>
     </>
  )
};

참고자료

Recoil 공식 홈페이지

0개의 댓글