코딩하는라민

[React] Recoil 상태 관리 라이브러리 설치 및 기본 본문

State Management/Recoil

[React] Recoil 상태 관리 라이브러리 설치 및 기본

코딩하는라민 2023. 3. 13. 22:39
728x90
반응형

[React] Recoil 상태 관리 라이브러리 설치 및 기본

📌 상태관리란?

상태는 컴포넌트 내부에서 변경이 일어나는 값을 관리하기 위한 모든 데이터를 말한다.

상태관리는 변경이 일어나는 값들을 관리하는 것이다.

 

상태관리는

  • 초기값을 저장할 수 있어야 하고,
  • 현재값을 읽을 수 있어야 하고,
  • 값을 업데이트할 수 있어야 한다.

함수형 컴포넌트에서 useState 로 자식 컴포넌트에서 부모 컴포넌트의 state 를 변경하여 상태관리를 할 수 있었다.

또 다른 방법이 하나 더 있는데 바로 상태관리 툴을 이용하는 것이다.

 

상태관리 툴은 다양한 종류가 존재한다.

  • Redux
  • Recoil
  • React query
  • MobX
  • apollo
  • useSWR
  • ...

 

📌 상태 공유 기능의 한계

기존에 사용하던 방식은 다음과 같은 한계점이 있다.

  1. 컴포넌트의 상태는 공통된 상위 요소까지 끌어올리기를 해야 공유될 수 있다.
    그 과정에서 props drilling 이라는 문제점이 생겨서 성능 저하의 원인이 되기도 한다.
  2. Context 를 이용해 위와 같은 문제점을 해결할 수 있지만, Context 는 단일 값만 저장할 수 있다는 단점이 있다.

위의 두 가지 특성이 state 가 존재하는 트리의 최상단 컴포넌트부터 state 가 사용되는 트리의 말단까지의 코드 분할을 어렵게한다.

 

📌 Recoil 이란?

2021 년에 페이스북에서 나온 리액트를 위한 상태관리 라이브러리이다.

Recoil 의 핵심은 Atoms 과 Selectors 로 이루어져있다.

Recoil 을 사용하면 Atoms 에서 selectors 를 거쳐 리액트 컴포넌트로 내려가는 데이터 흐름 그래프를 만들 수 있다.

 

Atoms Selectors
공유 상태 순수 함수
컴포넌트가 구독할 수 있는 상태 단위 Atoms 상태 값을 동기 또는 비동기 방식으로 전환

 

📌 Recoil 설치하기

✅ NPM 설치

npm install recoil
or
yarn add recoil

Recoil 을 사용하려면 React 가 설치되어 있어야 한다.

Recoil 은 웹팩이나 롤업과 같은 모듈 번들러와도 문제 없이 호환이 가능하다.

 

✅ CDN

<script src="https://cdn.jsdelivr.net/npm/recoil@0.0.11/umd/recoil.production.js"></script>

 

✅ ESLint

💡 ESLint 플러그인 설치하기

npm init @eslint/config

 

💡 eslint-plugin-react-hooks 플러그인 설치하기

npm i -D eslint-plugin-react-hooks

이 플러그인을 설치하게 되면 컴포넌트에 훅 등을 import 하지 않았을 경우 eslint  가 경고하며 알려준다.

 

💡 .eslintrc.cjs 파일 설정

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:react/jsx-runtime',
    'plugin:react-hooks/recommended',
  ],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  plugins: ['react', 'react-hooks'],
  rules: {
    'react/prop-types': 'off',
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': [
      'warn',
      {
        additionalHooks: 'useRecoilCallback',
      },
    ],
  },
};

 

📌 Recoil 사용하기

✅ RecoilRoot

recoil 상태를 사용하는 컴포넌트는 루트 컴포넌트에 RecoilRoot 가 필요하다.

FontButton 컴포넌트에 recoil 을 사용한다면 이를 감싸주는 곳에서 RecoilRoot 를 써줘야하는 것이다.

즉, Recoil의 hooks를 사용하는 모든 구성 요소의 조상이어야 한다.

import React from 'react';
import {
  RecoilRoot,
  atom,
  selector,
  useRecoilState,
  useRecoilValue,
} from 'recoil';

function App() {
  return (
    <RecoilRoot>
      <FontButton />
      <Text />
    </RecoilRoot>
  );
}

<RecoilRoot>는 여러개가 같이 존재할 수 있고, 각각이 독립적인 atom 상태의 providers/store가 된다.

 

📌 Atoms

Atoms 는 상태(state)의 일부를 나타낸다.

Atoms 는 컴포넌트가 구독할 수 있는 상태 단위인데, 업데이트 구독이 가능하다.

 

Atoms 는 어떤 컴포넌트에서나 읽고 쓸 수 있다.

atom 의 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독한다.

  • atoms 이 업데이트되면 구독중인 컴포넌트들은 리렌더링된다.
  • 런타임에서 생성될 수도 있음
  • 동일한 atoms 가 여러 컴포넌트에서 사용 되는 경우 모든 컴포넌트는 상태를 공유

 

✅ Atoms 는 atom 함수를 사용해 생성

atom 함수는 쓰기 가능한 RecoilState 객체를 반환한다.

const fontSizeState = atom({
    key: 'fontSizeState',
    default: 14,
});
  • key : 내부적으로 atom 을 식별하는데 사용되는 고유한 문자열. key 값은 전역적으로 고유하도록 설정해야한다.
  • default : atom의 초기값 또는 promise 또는 동일한 타입의 값을 나타내는 다른 atom 이나 selector.

 

atom 을 읽고 쓰려면 useRecoilState() 라는 훅을 사용한다.

useRecoilState() 는 상태가 컴포넌트 간에 공유될 수 있다.

atom 함수를 정의한 변수를 useRecoilState 의 인자에 넣어준다.

function FontButton() {
    const [fontSize, setFontSize] = useRecoilState(fontSizeState);
    return (
      <button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
        Click to Enlarge
      </button>
    );
}

버튼을 클릭하면 폰트 사이즈가 1씩 증가한다.

폰트 사이즈의 기본값은 14이므로 버튼을 누르면 14부터 1씩 증가하게 된다.

버튼의 style 은 인라인의 형태로 사용했다.

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

Text 컴포넌트에서도 폰트 사이즈 스타일을 적용할 수 있다.

 

📌 Selectors

Selector 는 atoms 나 다른 selectors 를 입력으로 받아 파생된 상태를 생성하는 순수 함수이다.

주어진 종속성 값 집합에 대해 항상 동일한 값을 반환하는 부작용이 없는 함수를 말한다.

 

Selector는 파생된 상태(derived state)의 일부를 나타낸다.

파생된 상태란 상태의 변화이다.

  • atoms 와 마찬가지로 상위의 atoms, selectors 가 업데이트되면 하위 selector 함수도 다시 실행된다.
  • 컴포넌트들은 selectors를 atoms처럼 구독할 수 있다.
  • selectors 가 변경되면 구독중인 컴포넌트들도 리렌더링된다.

 

✅ Selectors 는 selector 함수를 사용해 정의

get 함수만 제공되면 Selector 는 읽기만 가능한 RecoilValueReadOnly 객체를 반환한다.

set 함수 또한 제공되면 Selector 는 쓰기 가능한 RecoilState 객체를 반환한다.

 

Atoms 와 마찬가지로 고유한 key 설정이 필요하다.

get 메서드 내부에서 사용되는 get 함수는 Atoms 또는 다른 Selector를 전달받을 수 있다.

그럴 경우 자동으로 종속 관계가 생성되며, 참조했던 다른 Atoms, Selectors 가 업데이트 되면 다시 실행된다.

const fontSizeLabelState = selector({
    key: 'fontSizeLabelState',
    get: ({get}) => {
      const fontSize = get(fontSizeState);
      const unit = 'px';

      return `${fontSize}${unit}`;
    },
});

 

  • key : 내부적으로 atom 을 식별하는데 사용되는 고유한 문자열. 애플리케이션 전체에서 다른 atom 과 selector에 대해 고유해야한다.
  • get : 파생된 상태의 값을 평가하는 함수. 값을 직접 반환하거나 비동기적인 promise나 또는 같은 유형을 나타내는 다른 atom이나 selector 를 반환할 수 있다. 첫번째 매개변수로 다음 속성을 포함하는 객체를 전달한다.
    • get : 다른 atom 이나 selector 로부터 값을 찾는데 사용되는 함수. 이 함수에 전달된 모든 atom과 selector는 암시적으로 selector에 대한 의존성 목록에 추가된다. Selector의 의존성이 변경되면 Selector 가 다시 평가된다.
더보기
  • set : 이 속성이 설정되면 selector 는 쓰기 가능한 상태를 반환한다. 첫번째 매개변수로 콜백 객체와 새로 입력 값이 전달된다. 콜백에는 다음이 포함된다.
    • get : 다른 atom 이나 selector로부터 값을 찾는데 사용되는 함수. 이 함수는 selector를 주어진 atom 이나 selector를 구독하지 않는다.
    • set : 업스트림 Recoil 상태의 값을 설정할 때 사용되는 함수. 첫번째 매개변수는 Recoil 상태, 두 번째 매개변수는 새로운 값이다. 새로운 값은 업데이트 함수나 재설정 액션을 전파하는 DefalutValue 객체일 수 있다.

 

fontSizeLabelState(selector) 는 useRecoilValue() 를 사용해 읽을 수 있다.

useRecoilValue() 는 하나의 atom 이나 selector 를 인자로 받아 대응하는 값을 반환한다.

현재 상태에서는 fontSizeLabelState selector 는 읽을수만 있기 때문에 useRecoilState를 이용하지 않았다.

물론 useRecoilState 를 사용해서 인자 하나만 입력해서 사용할 수는 있다.

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 란?

더보기

처음에 공식문서에서 Selector 에 대해 읽어보고 정리해보았지만, 완벽하게 이해된 상태는 아니었다.

Selector 를 사용한 다른 블로그, 유튜브 예제들을 보면서 '파생된 상태'라는 말에 대해 조금은 이해가 되었다.

'파생되다' 라는 '어떤 근본이 되는 어떤 것으로부터 갈라져 나와 생기다'의 의미이다.

따라서 Selector 는 atom 에서 갈라져서 나와 생긴 것으로 atom 의 값을 가지고 조작해줄 수 있는 것으로 이해했다.

따라서 엑셀의 수식처럼 atom 의 값에 2배를 하는 함수를 반환하고싶다! 한다면 selector 를 이용해 useRecoilValue 를 이용해서 그 값을 2배로 만들어주도록 정의해줄 수 있다.

...

 

 


참고 : 리코일 공식 문서
  등을 공부하고, 간단하게 정리한 내용입니다. 잘못된 부분이나 문제되는 점이 있으면 댓글 부탁드립니다.

728x90
반응형