🗂️
EPISODE 08
전역 상태 · Zustand · slice · devtools
상태 관리 라이브러리 (Zustand)
전역 상태가 필요한 시점, Zustand vs Redux 비교, create로 store 만들기, 선택적 구독으로 성능 최적화, slice 패턴, devtools 미들웨어를 익힙니다.
Zustand전역 상태Redux
소요 시간
⏱ 45~60분
난이도
📊 중급~고급
선수 조건
🎯 react-07
결과물
Zustand로 만든 cart/user 전역 store
이 강의에서 배우는 것
- 1전역 상태가 필요한 시점을 판단한다
- 2Zustand와 Redux의 차이를 안다
- 3create로 store를 만들고 set으로 상태를 변경한다
- 4선택자로 필요한 상태만 구독해 리렌더링을 줄인다
- 5slice 패턴으로 관심사를 분리한다
- 6devtools 미들웨어로 디버깅한다
1. 전역 상태가 필요한 시점
| 상황 | 해결책 |
|---|---|
| 컴포넌트 내부 | useState |
| 부모-자식 전달 | props |
| 2~3단계 이상 props drilling | useContext |
| 여러 페이지/컴포넌트 공유 | 전역 상태 관리 |
| 복잡한 비동기 + 공유 상태 | 전역 상태 관리 |
장바구니, 로그인 사용자 정보, 알림, 언어 설정 등이 전형적.
2. Zustand vs Redux
| 항목 | Zustand | Redux Toolkit |
|---|---|---|
| 설치 크기 | ~1KB | 큰 편 |
| 학습 곡선 | 낮음 | 높음 |
| 보일러플레이트 | 거의 없음 | 어느 정도 |
| DevTools | 미들웨어로 | 기본 내장 |
| 비동기 | 자유롭게 | createAsyncThunk |
| 적합 규모 | 소~중 | 대규모 팀 |
3. Zustand 기본
bash
npm install zustandjsx
import { create } from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
function Counter() {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<p>{count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}4. 선택적 구독
jsx
// count만 구독 — count가 바뀔 때만 리렌더링
function CountDisplay() {
const count = useCounterStore((state) => state.count);
return <p>{count}</p>;
}
// increment만 구독 — 절대 리렌더링 안 됨 (함수는 변하지 않음)
function IncrementButton() {
const increment = useCounterStore((state) => state.increment);
return <button onClick={increment}>+</button>;
}5. slice 패턴
jsx
// store/slices/cartSlice.js
export const createCartSlice = (set, get) => ({
cart: [],
addToCart: (item) => set((state) => ({ cart: [...state.cart, item] })),
removeFromCart: (id) => set((state) => ({ cart: state.cart.filter(i => i.id !== id) })),
getTotal: () => get().cart.reduce((sum, item) => sum + item.price, 0),
});
// store/useAppStore.js
import { create } from 'zustand';
import { createCartSlice } from './slices/cartSlice';
import { createUserSlice } from './slices/userSlice';
const useAppStore = create((...args) => ({
...createCartSlice(...args),
...createUserSlice(...args),
}));6. devtools 미들웨어
jsx
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
const useStore = create(
devtools(
(set) => ({
count: 0,
increment: () => set((s) => ({ count: s.count + 1 }), false, 'increment'),
}),
{ name: 'MyStore' }
)
);Redux DevTools 확장과 연동돼 상태 변화를 시각적으로 확인.