Ch.22 React 심화 — 상태 관리 패턴
Zustand — 가벼운 상태 관리
Redux는 복잡하다 더 쉬운 방법이 있다
상태 관리 라이브러리를 검색하면 Redux가 나오지만 action, reducer, dispatch, store 설정에 100줄이 넘습니다.
상태 관리, 10줄이면 충분하지 않을까?
Zustand — 독일어로 '상태'. 최소한의 코드로 전역 상태를 관리합니다.
핵심 내용
Zustand은 Redux의 보일러플레이트를 95% 줄였습니다
create() 함수 하나로 상태와 액션을 한 번에 정의합니다
// stores/todo-store.ts
import { create } from "zustand";
interface Todo {
id: number;
text: string;
done: boolean;
}
interface TodoStore {
todos: Todo[];
addTodo: (text: string) => void;
toggleTodo: (id: number) => void;
removeTodo: (id: number) => void;
}
export const useTodoStore = create<TodoStore>((set) => ({
// 상태
todos: [],
// 액션
addTodo: (text) => set((state) => ({
todos: [...state.todos, {
id: Date.now(),
text,
done: false,
}],
})),
toggleTodo: (id) => set((state) => ({
todos: state.todos.map(t =>
t.id === id ? { ...t, done: !t.done } : t
),
})),
removeTodo: (id) => set((state) => ({
todos: state.todos.filter(t => t.id !== id),
})),
}));set() 함수의 원리 set()에 전달한 객체는 기존 상태와 얕은 병합(shallow merge)됩니다. 변경하고 싶은 필드만 반환하면 됩니다.
store를 훅처럼 호출하면 끝 Provider도 필요 없습니다
// 컴포넌트에서 사용
import { useTodoStore } from "@/stores/todo-store";
function TodoList() {
// 필요한 것만 선택적으로 구독
const todos = useTodoStore((s) => s.todos);
const toggleTodo = useTodoStore((s) => s.toggleTodo);
return (
<ul>
{todos.map((todo) => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id)}
style={{ textDecoration: todo.done ? "line-through" : "none" }}
>
{todo.text}
</li>
))}
</ul>
);
}
function AddTodo() {
const addTodo = useTodoStore((s) => s.addTodo);
const [text, setText] = useState("");
return (
<form onSubmit={(e) => {
e.preventDefault();
addTodo(text);
setText("");
}}>
<input value={text} onChange={(e) => setText(e.target.value)} />
<button type="submit">추가</button>
</form>
);
}바이브 코더 팁 AI에게 "Zustand store로 장바구니 상태 관리해줘"라고 하면 바로 사용할 수 있는 store 코드를 생성합니다.
Zustand을 사용하려면 Redux처럼 Provider로 앱을 감싸야 한다
Zustand에서 상태를 업데이트하는 함수는?
Zustand에서 성능 최적화를 위해 해야 하는 것은?
핵심 용어
보일러플레이트
Redux: action + reducer + dispatch / Zustand: create() 하나
Provider
Redux: Provider 필수 / Zustand: 불필요
번들 크기
Redux: ~16KB / Zustand: ~1KB
학습 곡선
Redux: 높음 / Zustand: 낮음 (5분이면 시작)
선택적 구독
s => s.todos처럼 필요한 값만 선택하면 해당 값이 바뀔 때만 리렌더
전체 구독 금지
useTodoStore()처럼 전체를 구독하면 어떤 값이든 바뀔 때마다 리렌더
정리 노트
Zustand 상태 관리 핵심 정리
Zustand 기본
- create()
- 스토어를 생성하고 상태와 액션을 정의
- selector
- useStore(s => s.count)처럼 필요한 값만 구독해서 리렌더링 최적화
- Provider 불필요
- Context와 달리 Provider 없이 어디서든 사용 가능
Context vs Zustand
- Context
- 간단한 전역 데이터(테마, 언어)에 적합, Provider 필요
- Zustand
- 복잡한 상태 로직, 빈번한 업데이트에 적합, 보일러플레이트 최소
Zustand는 selector로 필요한 값만 구독하면 불필요한 리렌더링을 방지할 수 있습니다.
퀴즈와 인터랙션으로 더 깊이 학습하세요
play_circle인터랙티브 레슨 시작