Zustand는 독일어로 'state'(상태)를 의미하며, React 애플리케이션을 위한 작고 빠르며 확장 가능한 상태 관리 라이브러리입니다.
🔗 공식 문서: https://docs.pmnd.rs/zustand/getting-started/introduction
// store/counterStore.js
import create from 'zustand'
// 기본 스토어 생성
const useStore = create((set) => ({
// 초기 상태
count: 0,
// 액션
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}))
set
: 상태를 업데이트하는 함수get
: 현재 상태를 가져오는 함수subscribe
: 상태 변화를 구독하는 함수// stores/counterStore.js
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 }), // 상태 초기화
}))
// Counter.js
function Counter() {
// 필요한 상태와 액션만 선택적으로 가져오기
const { count, increment, decrement, reset } = useCounterStore()
return (
<div>
<h1>카운트: {count}</h1>
<button onClick={decrement}>감소</button>
<button onClick={increment}>증가</button>
<button onClick={reset}>초기화</button>
</div>
)
}
// stores/todoStore.js
import create from 'zustand'
const useTodoStore = create((set, get) => ({
// 상태
todos: [],
isLoading: false,
error: null,
// 액션: 할 일 추가
addTodo: (todo) => set((state) => ({
todos: [...state.todos, {
id: Date.now(),
text: todo,
completed: false
}]
})),
// 액션: 할 일 삭제
removeTodo: (id) => set((state) => ({
todos: state.todos.filter(todo => todo.id !== id)
})),
// 액션: 할 일 토글
toggleTodo: (id) => set((state) => ({
todos: state.todos.map(todo =>
todo.id === id
? { ...todo, completed: !todo.completed }
: todo
)
})),
// 비동기 액션: 할 일 목록 가져오기
fetchTodos: async () => {
set({ isLoading: true })
try {
const response = await fetch('https://api.example.com/todos')
const todos = await response.json()
set({ todos, isLoading: false })
} catch (error) {
set({ error: error.message, isLoading: false })
}
},
// Computed 값: 완료된 할 일 개수
get completedCount() {
return get().todos.filter(todo => todo.completed).length
}
}))
// stores/advancedStore.js
import create from 'zustand'
import { persist, devtools } from 'zustand/middleware'
// 커스텀 미들웨어 예시
const log = (config) => (set, get, api) =>
config(
(...args) => {
console.log('이전 상태:', get())
set(...args)
console.log('다음 상태:', get())
},
get,
api
)
const useStore = create(
devtools( // Redux DevTools 연동
persist( // localStorage 연동
log( // 커스텀 로깅 미들웨어
(set, get) => ({
// 상태
user: null,
theme: 'light',
settings: {},
// 액션: 사용자 로그인
login: async (credentials) => {
const user = await authService.login(credentials)
set({ user })
},
// 액션: 테마 토글
toggleTheme: () => set((state) => ({
theme: state.theme === 'light' ? 'dark' : 'light'
})),
// 액션: 설정 업데이트
updateSettings: (newSettings) => set((state) => ({
settings: { ...state.settings, ...newSettings }
})),
})
),
{
name: 'app-storage', // localStorage 키 이름
whitelist: ['theme', 'settings'] // 저장할 상태 선택
}
)
)
)
// 필요한 상태만 구독하여 불필요한 리렌더링 방지
const todos = useTodoStore(state => state.todos)
const completedCount = useTodoStore(state =>
state.todos.filter(todo => todo.completed).length
)
// 전체 상태 초기화
const resetStore = useStore.setState(initialState)
// 특정 상태만 초기화
const resetCount = useStore.setState({ count: 0 })
const useAsyncStore = create((set) => ({
data: null,
isLoading: false,
error: null,
fetchData: async () => {
set({ isLoading: true })
try {
const response = await fetch('...')
const data = await response.json()
set({ data, isLoading: false })
} catch (error) {
set({ error, isLoading: false })
}
}
}))
interface TodoState {
todos: Todo[]
addTodo: (text: string) => void
removeTodo: (id: number) => void
}
const useTodoStore = create<TodoState>((set) => ({
todos: [],
addTodo: (text) => set((state) => ({
todos: [...state.todos, { id: Date.now(), text, completed: false }]
})),
removeTodo: (id) => set((state) => ({
todos: state.todos.filter(todo => todo.id !== id)
}))
}))
Zustand는 간단하면서도 강력한 상태 관리 라이브러리입니다. 특히:
이러한 특징들 때문에 많은 개발자들이 Redux나 Recoil 대신 Zustand를 선택하고 있습니다.
특히 작은 규모의 프로젝트부터 중간 규모의 프로젝트까지 Zustand는 매우 효과적인 선택이 될 수 있습니다. 복잡한 상태 관리가 필요하지 않은 프로젝트에서는 과도한 보일러플레이트 없이 깔끔한 코드를 유지할 수 있습니다.