# 11. 세 가지 전역 상태 라이브러리의 유사점과 차이점

> 마지막으로 Zustand, Jotai, Valtio를 비교해 보자!

\


## 🔖 1. 세 가지 라이브러리 설명해보기

### Zustand

* 사용법과 Store 모델 측면에서 Redux(or React Redux)와 유사하다. 다만 Redux처럼 action/reducer 구조를 강제하지 않는다.
* Redux와는 달리 reducer 함수를 기반으로 하지 않으므로, 보일러플레이트가 적고 러닝 커브가 낮다.
* 한마디로 Redux보다 Zustand가 자유도가 높다. 뭔가 강제하는 게 적기에 쉽게 느껴진다. (책에서는 '구조에 대한 의견을 제시하지 않는다고 표현)
* `useStore` 훅으로 전역 상태를 가져오고, 간단한 `setter`를 정의하는 식으로 작업한다.
* Selector 기반 최적화: `useStore(selector, equalityFn)` 형태로 원하는 상태만 구독할 수 있어, 불필요한 리렌더링을 줄일 수 있다.

### Jotai

* Recoil처럼 atom 단위로 상태를 관리하지만, 별도의 selector API를 쓰지 않는다. 대신 atom을 결합하거나 derived atom으로 만들어 필요한 상태를 구성한다.
* 필요한 atom만 구독하므로, atom이 바뀌지 않는 한 컴포넌트가 다시 렌더링되지 않는다. Context 설정 없이도 전역 상태를 다룰 수 있다.
* 여러 작은 atom을 쪼개서 관리하거나, atom을 결합해 복잡한 로직을 만들 수 있다. 그래서 프로젝트 규모가 커져도 비교적 유연한 구조로 유지 가능하다.
* 그래서 보통 Recoil 썼던 팀들이 Recoil이 저물고 나서 Jotai로 많이들 갈아타는 것 같다.

### Valtio

* 변경 가능한(mutable) 갱신 모델이라는 점에서 MobX와 유사하지만, Valtio는 Proxy를 통해 속성 변경을 자동 감지하는 것이 포인트다.
* 컴포넌트가 실제로 읽은 속성이 바뀔 때만 재렌더링하도록 해준다. Redux 등에서 요구되는 불변성 관리 없이 `state.count++`처럼 직관적으로 작성할 수 있다.
* 장점으로는 배우기 쉽고, 직관적인 코드 작성이 가능하다.
* 단점으로는 대규모 프로젝트에서 명시적 액션/리듀서 방식에 익숙한 개발자에겐 추적 로직이 얼렁뚱땅 이루어진 것처럼 (매우 추상적으로) 보일 수 있기에 디버깅이 어려울 수 있다.

\


## 🔖 2. 세 가지 라이브러리 표로 비교하기

> Thanks to GPT (❁´◡\`❁)

| 라이브러리       | 핵심 개념/사용 방식                                                                                                                  | 주요 특징                                                                     | 장점                                                                                                  | 단점                                                                                                 |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| **Zustand** | <p>- 단일(또는 소수의) Store 객체<br>- <code>useStore</code> 훅을 통해 상태/액션 사용<br>- Redux-like 구조(그러나 reducer/action 강제 X)</p>           | <p>- 설정이 매우 간단, 보일러플레이트 적음<br>- 원하는 상태만 구독(Selector+Equality)</p>         | <p>- 자유도가 높고, 러닝 커브가 낮다.<br>- 필요한 부분만 구독 가능 → 불필요 렌더링 ↓</p>                                         | <p>- 구조를 강제하지 않아, 규모가 커지면 설계가 제각각일 수 있음<br>- DevTools/미들웨어 생태계는 Redux만큼 크지 않음</p>                  |
| **Jotai**   | <p>- <strong>atom</strong>(원자) 단위로 상태 정의<br>- <code>useAtom</code> 훅으로 atom 읽기/쓰기<br>- Recoil 유사(Selector 대신 파생 atom 사용)</p> | <p>- 필요한 atom만 읽으므로, 다른 atom이 변해도 영향 X<br>- Context 설정 없이 전역 상태 관리 가능</p> | <p>- 작은 단위 상태를 여러 atom으로 나누고, 조합하는데 유연<br>- 쉽게 배우고 적용 가능<br>- atom 간 결합(파생 atom)으로 복잡 로직도 구성 가능</p> | <p>- atom이 너무 많아지면 구조 관리가 복잡<br>- 공식 DevTools는 다소 제한적 (Recoil만큼 성숙 X)</p>                          |
| **Valtio**  | <p>- <strong>Proxy</strong> 기반<br>- <code>useSnapshot</code> 훅으로 상태 스냅샷 사용<br>- <code>state.someProp++</code>처럼 직접 수정 가능</p> | <p>- 변경 가능한 갱신 방식<br>- 컴포넌트가 실제 읽은 속성만 업데이트 (자동 추적)</p>                   | <p>- 매우 직관적이고 자유로운 문법<br>- 불변성 관리, 코드 간결<br>- 부분 렌더링 최적화 자동화</p>                                    | <p>- 무분별한 상태 변경 시 추적 비용 증가 가능<br>- 대규모 프로젝트에서 액션/리듀서 기반이 아니라 디버깅 어려움<br>- DevTools/미들웨어 생태계 적음</p> |

\


## 🔖 3. 책을 덮으며

> "기본적으로 마이크로 상태 관리는 특정 문제에 대한 올바른 해결책과 라이브러리를 선택하는 것을 수반한다. 마이크로 상태 관리를 하기 위해서는 문제가 무엇이고, 문제에 사용 가능한 해결책이 무엇인지 이해하는 것이 필요하다. 이 책이 개발자들이 올바른 해결책을 찾는 데 도움이 되기를 바란다."

### 좋은 의사 결정이란

* 책의 말미에 나오는 이 문장이 이 책을 읽고 적용하는데에 갖추면 좋을 태도인 것 같다.
* 특정 기술 스택을 도입할 때 "\~는 \~라이브러리를 쓴다"는 이유는 별로 좋지 않다. "어디는 \~한 이유로 \~라이브러리를 쓴다, 우리도 \~한 문제가 있으니 \~라이브러리를 써서 해결해보자"가 더 좋은 의사 결정이다.

### 리팩토링을 하며 든 생각들

* 기존 코드에서는 모든 상태가 마구잡이로 Context API를 사용했기에 굳이 전역으로 관리하지 않아도 되는 것을 전역으로 관리하고 있었다.
* 리팩토링을 하며 가장 중점에 둔 것은 어떤 것을 전역으로 관리하고 (Context에 남겨두고) 어떤 것을 지역으로 관리할 것인지 분류하는 것이었다. 처음엔 서비스 단위, 그 다음에는 페이지 단위, 그리고 컴포넌트 단위, 함수 단위, .. 그리고 작은 상태 단위로 코드를 분석하고 동료와 논의하며 하나씩 하나씩 Context로부터 떼어냈다.
* Context로부터 의존성을 떼어내고, 복잡한 로직이 단순화되고, 모듈화가 되며 해당 컴포넌트를 어디서든 쓸 수 있게 되었고, 코드 라인을 획기적으로 줄였음에도 기능은 모두 정상적으로 작동되었다. 심지어 불필요한 렌더링을 줄여 깜빡임이나 속도도 줄었다. 근 한 달 넘게 이 부분을 두고 씨름했는데 실타래 풀리듯 문제가 풀리니 뿌듯했다.

### 이제는 적용할 때

* 이제는 전역 상태 라이브러리를 사용하며 남겨둔 전역 상태들을 '더 잘' 사용할 일만 남았다.
* 아직 Zustand를 쓸지 Jotai를 쓸지 결정을 못했는데, 만약 사용하게 된다 해도 우리가 처한 문제에 대응되는(즉, 해결할 수 있는) 라이브러리를 도입해야겠다.
