Contents
see List작성일 2025. 11. 30.
Zustand - 간단한 React 상태 관리
Zustand는 React를 위한 경량 상태 관리 라이브러리입니다. Redux보다 훨씬 간단하고, Context API의 리렌더링 문제를 해결합니다. 보일러플레이트 없이 직관적인 API를 제공합니다.
언제 사용하나요?
- 전역 상태가 필요하지만 Redux는 과한 경우
- 여러 컴포넌트에서 공유하는 상태 관리
- Context의 불필요한 리렌더링 방지
- 비동기 액션이 빈번한 경우
설치 및 기본 사용
npm install zustand
// store.js
import { create } from "zustand";
const useStore = create((set) => ({
// 상태
count: 0,
user: null,
// 액션
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
setUser: (user) => set({ user }),
reset: () => set({ count: 0, user: null }),
}));
export default useStore;컴포넌트에서 사용
import useStore from "./store";
function Counter() {
// 필요한 상태만 구독 (선택적 리렌더링)
const count = useStore((state) => state.count);
const increment = useStore((state) => state.increment);
return (
<div>
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
}
// 여러 상태 한번에 가져오기
function Profile() {
const { user, setUser } = useStore((state) => ({
user: state.user,
setUser: state.setUser,
}));
return <div>{user?.name}</div>;
}비동기 액션
const useStore = create((set, get) => ({
users: [],
loading: false,
error: null,
fetchUsers: async () => {
set({ loading: true, error: null });
try {
const res = await fetch("/api/users");
const users = await res.json();
set({ users, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
},
// get()으로 현재 상태 접근
addUser: async (user) => {
const { users } = get();
await api.createUser(user);
set({ users: [...users, user] });
},
}));미들웨어 - persist (로컬 스토리지)
import { create } from "zustand";
import { persist } from "zustand/middleware";
const useStore = create(
persist(
(set) => ({
theme: "light",
setTheme: (theme) => set({ theme }),
}),
{
name: "app-storage", // localStorage 키
partialize: (state) => ({ theme: state.theme }), // 일부만 저장
}
)
);미들웨어 - devtools
import { devtools } from "zustand/middleware";
const useStore = create(
devtools(
(set) => ({
count: 0,
increment: () => set(
(state) => ({ count: state.count + 1 }),
false,
"increment" // 액션 이름 (DevTools에 표시)
),
}),
{ name: "MyStore" }
)
);슬라이스 패턴 (대규모 스토어)
// userSlice.js
const createUserSlice = (set) => ({
user: null,
login: (user) => set({ user }),
logout: () => set({ user: null }),
});
// cartSlice.js
const createCartSlice = (set) => ({
items: [],
addItem: (item) => set((s) => ({
items: [...s.items, item]
})),
});
// store.js
const useStore = create((...a) => ({
...createUserSlice(...a),
...createCartSlice(...a),
}));컴포넌트 외부에서 사용
// API 호출 등에서 직접 사용
const { getState, setState, subscribe } = useStore;
// 현재 상태 조회
const currentUser = getState().user;
// 상태 변경
setState({ count: 10 });
// 상태 변화 구독
const unsubscribe = subscribe(
(state) => state.user,
(user) => console.log("User changed:", user)
);Redux vs Zustand 비교
| 항목 | Redux | Zustand |
|---|---|---|
| 보일러플레이트 | 많음 | 최소 |
| 러닝커브 | 높음 | 낮음 |
| 번들 크기 | ~12KB | ~1KB |
| Provider 필요 | 필수 | 불필요 |
| 미들웨어 | 풍부 | 기본 제공 |
javascript
| No | 작성일 | Title |
|---|---|---|
| 3384 | 2026. 08. 21. | Node.js API에서 요청 취소를 제대로 처리하는 방법: AbortSignal로 외부 작업 정리하기 |
| 3352 | 2026. 08. 13. | Node.js 응답이 간헐적으로 느릴 때: 이벤트 루프 지연 측정과 CPU 작업 분리 방법 |
| 3320 | 2026. 08. 04. | JavaScript fetch 요청을 안전하게 만드는 방법: timeout·재시도·오류 처리 실전 패턴 |
| 3288 | 2026. 07. 27. | Node.js 서버 무중단 배포를 위한 Graceful Shutdown 구현 가이드 |
| 3257 | 2026. 07. 19. | Node.js 대용량 파일 처리 가이드: 스트림과 backpressure로 메모리 사용량 제어하기 |
| 3232 | 2026. 07. 11. | Node.js 실무형 에러 처리: async/await에서 실패를 일관되게 분류하고 복구 속도 높이기 |
| 3174 | 2026. 07. 02. | Node.js 환경 변수 검증 가이드: process.env를 안전한 설정 객체로 바꾸기 |
| 3123 | 2026. 06. 24. | TypeScript 타입 좁히기 운영 가이드: unknown 입력을 안전한 도메인 객체로 바꾸기 |
| 3065 | 2026. 06. 16. | 브라우저 성능 병목 찾기: PerformanceObserver로 LCP·INP·긴 작업 로그 수집하기 |
| 2978 | 2026. 06. 08. | Node.js fetch 타임아웃과 재시도 설계: 외부 API 장애 전파 줄이기 |