DEV Community

Cover image for 전역 상태 관리 Recoil과 Zustand
Heetae Kim
Heetae Kim

Posted on • Edited on

전역 상태 관리 Recoil과 Zustand

Recoil과 Zustand는 React 애플리케이션에서 상태 관리를 도와주는 라이브러리이다. 두 라이브러리 근본적인 기능은 같지만, 서로 다른 방식으로 상태 관리를 구현하여 사용된다.

 

Recoil

Recoil은 Facebook에서 개발한 상태 관리 라이브러리로, React와 긴밀하게 통합되어 있으며, 주로 atom과 selector를 사용한다. Recoil은 비동기 상태 관리와 Tree Shaking을 지원하며, 복잡한 상태 관리가 필요한 큰 규모의 애플리케이션에 적합하다.

Atom과 Selector:

  • Atom : 상태의 기본 단위 이다. 상태를 읽고 쓸 수 있다.
  • Selector : 파생된 상태를 생성하는 데 사용된다. 다른 atom 또는 selector의 값을 기반으로 새로운 값을 계산할 수 있다.

비동기 상태 관리:

  • Recoil은 비동기 상태 관리 기능을 내장하고 있어, 네트워크 요청과 같은 비동기 작업을 쉽게 처리할 수 있다.

Tree Shaking:

  • 사용하지 않는 상태와 로직은 번들에서 제거되어 성능을 최적화할 수 있다.
// store.js
import { atom, selector } from 'recoil';

export const textState = atom({
  key: 'textState', // unique ID (with respect to other atoms/selectors)
  default: '', // 초기값 설정(default value)
});

export const charCountState = selector({
  key: 'charCountState', // unique ID
  get: ({ get }) => {
    const text = get(textState);
    return text.length;
  },
});
Enter fullscreen mode Exit fullscreen mode
// App.js
import React from 'react';
import { RecoilRoot } from 'recoil';
import CharacterCounter from './CharacterCounter';

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

export default App;
Enter fullscreen mode Exit fullscreen mode
// CharacterCounter.js
import { useRecoilState, useRecoilValue } from 'recoil';
import { textState, charCountState } from '/store'

function CharacterCounter() {
  return (
    <div>
      <TextInput />
      <CharacterCount />
    </div>
  );
}

function TextInput() {
  const [text, setText] = useRecoilState(textState); // text 구독

  const onChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
      <br />
      Echo: {text}
    </div>
  );
}

function CharacterCount() {
  const count = useRecoilValue(charCountState); // count 구독

  return <>Character Count: {count}</>;
}

export default CharacterCounter;
Enter fullscreen mode Exit fullscreen mode

 

Zustand

Zustand는 가볍고 사용하기 쉬운 상태 관리 라이브러리로, 단순한 상태 관리 패턴을 제공한다. 간단한 API로 작은 규모의 프로젝트에 적합하다.

초소형 및 간단한 API:

  • Zustand는 매우 간단한 API를 제공하며, 상태를 설정하고 구독하는 방식이 직관적이다.

미들웨어 지원:

  • 상태 변경을 감지하고, 로깅, 비동기 작업 등을 처리할 수 있는 미들웨어를 지원한다.

React 훅 기반

  • 훅을 사용하여 상태를 관리하며, recoil 처럼 별도의 Provider를 사용할 필요가 없다.

좋은 성능:

  • 블필요한 리렌더링을 최소화하고, 작은 번들 크기로 성능을 최적화 할 수 있다.
// store.js
import create from 'zustand';

const useStore = create((set) => ({
  text: '',
  setText: (text) => set({ text }),
  charCount: () => get().text.length,
}));
Enter fullscreen mode Exit fullscreen mode
// App.js
import CharacterCounter from './CharacterCounter';

function App() {
  return (
    <div>
      <CharacterCounter />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode
// CharacterCounter.js
import { useStore } from './store';

function CharacterCounter() {
  return (
    <div>
      <TextInput />
      <CharacterCount />
    </div>
  );
}

function TextInput() {
  const { text, setText } = useStore((state) => state); // text 구독

  const onChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
      <br />
      Echo: {text}
    </div>
  );
}

function CharacterCount() {
  const charCount = useStore((state) => state.charCount); // charCount 구독

  return <>Character Count: {charCount}</>;
}

export default CharacterCounter;
Enter fullscreen mode Exit fullscreen mode

💡

Zustand 내부에 store를 만드는 코드를 보자면, setState가 partialreplace로 나눠져 있는데, partial은 state의 일부분만 변경하고 싶을 때 사용하고, replace는 state를 완전히 새로운 값으로 변경하고 싶을 때 사용한다.

subscirbe 함수는 listener를 등록하는데, listener는 마찬가지로 Set 형태로 선언되어 추가와 삭제, 그리고 중복 관리가 용이하게끔 설계되어 있다. 즉, 상태값이 변경될 때 리렌더링이 필요한 컴포넌트에 전파될 목적으로 만들어 진 것이다.

destroy는 listener를 초기화하는 역할을 한다.

createStore는 이러한 getState, setState, subscribe, destory를 반환한다.

 

비교

복잡성:

  • Recoil은 Atom과 Selector 등 더 많은 개념이 필요하여 복잡하지만, 복잡한 상태 관리에 유리하다. 반면 Zustand는 단순한 API로 직관적이며, 작은 프로젝트에 적합하다.

비동기 상태 관리:

  • Recoil은 비동기 상태 관리를 기본적으로 지원한다. Zustand 역시 비동기 작업을 처리할 수 있지만, Recoil 만큼의 기본 지원은 없다.

퍼포먼스:

  • Recoil의 경우 Tree Shaking과 최적화된 상태 관리로 큰 애플리케이션에서도 좋은 성능을 보인다. 반면 Zustand는 매우 가벼운 라이브러리로 불필요한 리렌더링을 최소화하여 성능을 최적화 한다.

  • Recoil은 라이브러리 업데이트 주기가 오래 되어 안정성이 낮으며, Zustand는 최근에 나왔지만 최신 업데이트로 안정성이 개선되고 있다.

 

마무리

Recoil과 Zustand는 각각의 장단점이 있으며, 프로젝트의 요구 사항에 따라 적절한 라이브러리를 선택하여 사용하면 된다.

Top comments (0)