📡 Zustand
Zustand는 React를 위한 경량 상태 관리 라이브러리로,
복잡한 보일러플레이트 없이 전역 상태를 직관적으로 관리할 수 있도록 설계되었습니다.
Redux처럼 전역 상태를 관리하지만,
- Provider 불필요
- reducer/action 강제 ❌
- hook 기반 API
를 통해 React스럽고 간력한 사용성을 제공합니다.
1️⃣ Zustand가 필요한 이유
React의 기본 상태 관리(useState, useContext)는 규모가 커질수록 한계를 드러냅니다.
🔹 기존 방식의 문제점
-
props drilling
- 깊은 컴포넌트 트리에서 상태 전달
- 유지보수 어려움
-
Context 남용
- 작은 상태 변경에도 전체 리렌더링
- 로직 분산
-
Redux의 부담
- action / reducer / dispatch
- 설정 비용 큼
👉 Zustand는 이 문제를 다음 철학으로 해결합니다.
“상태는 외부에 두고, 컴포넌트는 필요한 것만 구독한다”
2️⃣ 핵심 개념 요약
- Store는 단 하나의 JS 객체
- 상태 변경은 함수 기반(set)
- 컴포넌트는 필요한 상태만 선택적으로 구독
- 불필요한 리렌더링 최소화
3️⃣ 기본 사용법
🔹 Store 생성
import { create } from "zustand";
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ state.count + 1 })),
decrement: () => set((state) => ({ state.count - 1 }))
}))
컴포넌트에서 사용
function Counter() {
const { count, increment, decrement } = useCounterStore();
return (
<>
<p>{count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</>
);
}
✔️ Provider 없이 바로 사용 가능
✔️ 상태 변경 시 해당 상태를 구독한 컴포넌트만 리렌더링
4️⃣ Zustand의 핵심 구조
Zustand store는 내부적으로 다음 구조를 가집니다.
Store
├─ state (객체)
├─ set (상태 변경 함수)
├─ get (현재 상태 조회)
└─ subscribers (구독자 목록)
set→ 상태 변경- 상태 변경 시 → 구독 중인 컴포넌트만 알림
✔️ React 외부에 존재하는 독립적인 상태 저장소
5️⃣ Selector와 리렌더링 최적화
Zustand의 강점은 선택적 구독입니다.
const count = useCounterStore((state) => state.count);
count가 바뀔 때만 리렌더링- 다른 상태 변경은 무시
📌 Redux useSelector와 유사하지만 더 단순
6️⃣ 주요 미들웨어
Zustand 미들웨어는 store 생성 과정에 개입하여 동작을 확장하는 기능입니다.
🔹 presist - 상태 영속화
import { persist } from "zustand/middleware";
export const useAuthStore = create(
persist(
(set) => ({
token: null,
login: (token: string) => set({ token }),
logout: () => set({ token: null }),
}),
{
name: "auth-storage",
}
)
);
- localStorage / sessionStorage 저장
- 새로고침 후에도 상태 유지
📌 로그인 정보, 설정 값에 유용
🔹 devtools - Redux DevTools 연동
import { devtools } from "zustand/middleware";
export const useCounterStore = create(
devtools((set) => ({
count: 0,
increment: () => set((s) => ({ count: s.count + 1 }), false, "increment"),
}))
);
- 상태 변경 히스토리 확인
- time-travel debugging 가능
🔹 immer - 불변성 관리 단순화
import { immer } from "zustand/middleware";
export const useTodoStore = create(
immer((set) => ({
todos: [],
addTodo: (todo) =>
set((state) => {
state.todos.push(todo);
}),
}))
);
- 불변 객체 직접 수정하는 것처럼 작성
- 내부적으로 immutable 처리
🔹 subscribeWithSelector
import { subscribeWithSelector } from "zustand/middleware";
- 특정 상태 변화만 감지
- React 외부 로직에서도 상태 구독 가능
7️⃣ 미들웨어 조합
Zustand 미들웨어는 체이닝 가능
create(
devtools(
persist(
immer((set) => ({
count: 0,
})),
{ name: "counter" }
)
)
);
- 순서 중요
- store 생성 단계에서 래핑됨