리액트 상태 관리 심화 #6 어떤 도구를 언제 — 결정 가이드
시리즈의 마지막 글입니다. #1에서 상태를 클라이언트 상태와 서버 상태로 나눴고, #2에서 #5까지 도구를 하나씩 봤습니다. 이번 글은 이 모두를 한 장의 결정 흐름으로 묶습니다. 새 화면을 만들 때 실제로 어떤 순서로 질문하고 판단하면 되는지를 정리하는 것이 목표입니다.
가장 먼저 던질 질문 #
#1의 결론을 다시 가져옵니다. 어떤 상태를 만나든 첫 질문은 하나입니다.
“이 값은 브라우저 안에서 완결되나, 아니면 서버 데이터의 사본인가?”
이 한 질문이 절반을 가릅니다.
- 서버 데이터의 사본이면 → 서버 상태입니다. 전역 저장소에 넣지 말고 TanStack Query에 맡깁니다.
- 브라우저 안에서 완결되면 → 클라이언트 상태입니다. 다음 질문으로 넘어갑니다.
결정 흐름 한 장 #
이 값은 무엇인가?
│
├─ 서버 데이터의 사본 (목록,상세,검색 결과)
│ → TanStack Query (#2)
│ 캐싱,재요청,신선도는 도구에 맡긴다
│
└─ 브라우저 안에서 완결되는 클라이언트 상태
│
├─ 한 컴포넌트(또는 바로 아래 자식)에서만 쓴다
│ → useState / useReducer (빌트인)
│
├─ 여러 컴포넌트가 공유하지만 값이 거의 안 바뀐다
│ (테마, 로케일, 로그인 사용자 정보 등)
│ → useContext 로 충분
│
└─ 여러 컴포넌트가 공유하고 자주 바뀐다
│
├─ 가볍게, 보일러플레이트 최소로
│ → Zustand (#3) ── 하나의 스토어 + 셀렉터
│ → Jotai (#4) ── 작은 원자 + 파생 원자
│
└─ 큰 팀,엄격한 변경 규약,강한 추적성이 필요
또는 이미 Redux 코드베이스
→ Redux Toolkit (#5)빌트인을 건너뛰지 말 것 #
도구를 다섯 개나 봤지만, 가장 많이 쓰게 될 것은 여전히 useState입니다. 새 라이브러리는 여러 컴포넌트가 공유 + 트리에서 멀리 떨어짐이라는 조건이 겹칠 때 비로소 값어치를 합니다. 그 전에는 빌트인이 가장 단순하고 가장 빠릅니다.
도구를 하나 늘리는 것만으로도 번들 크기, 학습 비용, 새 팀원의 진입 장벽 같은 비용이 생깁니다. “이 상태에 정말 전역 저장소가 필요한가"를 먼저 의심하는 습관이 좋은 설계로 이어집니다.
Zustand vs Jotai — 무엇으로 가를까 #
둘 다 가볍고 Provider가 없어 직접 비교가 잦습니다. #3과 #4에서 본 차이를 한 표로 정리합니다.
| 기준 | Zustand | Jotai |
|---|---|---|
| 모델 | 하향식 — 하나의 스토어 | 상향식 — 작은 원자 조립 |
| 잘 맞는 상태 | 한 덩어리로 묶이는 전역 상태 | 서로 의존하는 파생 값이 많은 상태 |
| 리렌더 통제 | 셀렉터로 부분 구독 | 원자 단위로 자연히 분리 |
| 사용 감각 | “전역 스토어를 하나 둔다” | “useState를 전역으로 쪼개 쓴다” |
정답은 없습니다. 상태가 자연스럽게 한 덩어리로 묶이면 Zustand가, 값들이 서로 참조하며 파생되는 구조라면 Jotai가 더 깔끔합니다. 팀이 익숙한 쪽을 고르는 것도 충분히 타당한 기준입니다.
흔한 함정 다섯 가지 #
시리즈를 관통하며 반복해 강조한 실수들을 모았습니다.
1. 서버 데이터를 전역 클라이언트 저장소에 넣기. 가장 흔하고 비용이 큰 실수입니다. 캐싱과 재요청을 손으로 다시 만들게 됩니다. 서버 상태는 TanStack Query(또는 RTK Query)에 맡깁니다.
2. 모든 상태를 하나의 거대한 전역 객체에 몰기. 한 곳이 바뀔 때 관련 없는 컴포넌트까지 리렌더되기 쉽습니다. 셀렉터나 원자 단위로 상태를 쪼개 구독을 좁힙니다.
3. 지역 상태까지 전역으로 끌어올리기. 폼 입력값 하나, 토글 하나는 useState로 충분합니다. 전역화는 공유가 진짜 필요할 때만 합니다.
4. 도구를 너무 많이 섞기. 한 앱에 Redux와 Zustand와 Jotai를 동시에 두면 새 팀원이 “이 상태는 어디 있지"를 매번 헤맵니다. 클라이언트 상태 도구는 하나로 정하는 편이 좋습니다.
5. 리렌더를 측정하지 않고 추측하기. “느릴 것 같아서” 도구를 바꾸기 전에 React DevTools Profiler로 실제 리렌더를 확인하시기 바랍니다. 대개 문제는 도구가 아니라 구독 범위에 있습니다.
현실적인 조합 #
실무에서 자주 보는 안정적인 조합은 단순합니다.
서버 상태 → TanStack Query
클라이언트 상태 → Zustand 또는 Jotai 중 하나
지역 상태 → useState / useReducer
거의 바뀌지 않는 정적 전역값 → useContext (테마,로케일 등)도구를 더 늘리기 전에, 이 네 칸으로 대부분의 앱이 깔끔하게 정리됩니다. 핵심은 상태의 종류를 먼저 구분하고, 종류마다 알맞은 칸에 두는 것입니다.
시리즈를 마치며 #
여섯 편을 관통한 메시지는 처음과 같습니다. 도구를 외우기 전에 상태의 성질을 먼저 구분하라.
- 상태에는 클라이언트 상태와 서버 상태가 있고, 둘은 잘 맞는 도구가 다릅니다. (#1)
- 서버 상태는 TanStack Query에 맡겨 캐싱과 재요청을 자동화합니다. (#2)
- 가벼운 전역 클라이언트 상태에는 Zustand나 Jotai가 어울립니다. (#3, #4)
- Redux Toolkit은 큰 팀과 기존 코드베이스에서 여전히 제 역할을 합니다. (#5)
상태 관리는 정답을 외우는 분야가 아니라, 상황을 읽고 알맞은 도구를 고르는 분야입니다. 새 화면을 만날 때마다 “이 값은 어떤 종류의 상태인가"를 먼저 묻는다면, 어떤 도구를 꺼낼지는 자연히 따라옵니다.
이상으로 “리액트 상태 관리 심화” 시리즈를 마칩니다. 더 깊은 주제로는 모던 리액트 + Next.js 시리즈의 Server Components 환경에서 클라이언트 상태와 서버 상태가 어떻게 나뉘는지를 이어 읽어보시길 권합니다.