전역 상태 관리 Recoil과 Zustand
Tags: recoil, zustand
Published: 2024-06-19 15:59:47

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

&nbsp;

## Recoil

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

### Atom과 Selector:

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

### 비동기 상태 관리:

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

### Tree Shaking:

- 사용하지 않는 상태와 로직은 번들에서 제거되어 성능을 최적화할 수 있다.

```js
// 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;
  },
});
```

```jsx
// App.js
import React from 'react';
import { RecoilRoot } from 'recoil';
import CharacterCounter from './CharacterCounter';

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

export default App;
```

```jsx
// 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;
```

&nbsp;

## Zustand

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

### 초소형 및 간단한 API:

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

### 미들웨어 지원:

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

### React 훅 기반

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

### 좋은 성능:

- 블필요한 리렌더링을 최소화하고, 작은 번들 크기로 성능을 최적화 할 수 있다.

```js
// store.js
import create from 'zustand';

const useStore = create((set) => ({
  text: '',
  setText: (text) => set({ text }),
  charCount: () => get().text.length,
}));
```

```jsx
// App.js
import CharacterCounter from './CharacterCounter';

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

export default App;
```

```jsx
// 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;
```

💡

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

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

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

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

&nbsp;

## 비교

### 복잡성:

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

### 비동기 상태 관리:

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

### 퍼포먼스:

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

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

&nbsp;

## 마무리

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