
Zustand là gì và tại sao nên dùng
Zustand là thư viện quản lý state cho React, được tạo bởi Daishi Kato thuộc tổ chức pmndrs (cùng team với react-three-fiber). Tên gọi lấy từ tiếng Đức có nghĩa “căn phòng”, mascot là một chú gấu nâu dễ thương. Tính đến nay Zustand đã thu hút hơn 58.000 stars trên GitHub và có hơn 198 triệu lượt tải về mỗi tháng trên npm, xếp thứ hai chỉ sau Redux về lượng sử dụng trong hệ sinh thái React.
Vấn đề lớn nhất của state management trong React là sự phức tạp. Redux yêu cầu bạn viết actions, reducers, action types, và thường cần Provider bao quanh toàn bộ ứng dụng. Context API đơn giản hơn nhưng lại gây re-render toàn bộ subtree khi giá trị thay đổi. Zustand giải quyết cả hai vấn đề này bằng cách cung cấp một API cực kỳ gọn nhẹ dựa trên React hooks, không cần Provider, không cần boilerplate.

Cài đặt và cấu hình cơ bản
Việc cài đặt Zustand cực kỳ đơn giản. Thư viện không có bất kỳ dependency nào (v5), nghĩa là bundle size gần như bằng không so với các giải pháp khác.
npm install zustand
Sau khi cài đặt, bạn có thể tạo store đầu tiên chỉ với vài dòng code:
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 }),
}))
Điểm đặc biệt nhất: bạn không cần bọc ứng dụng trong Provider nào cả. Store là một React hook, dùng trực tiếp trong component bằng cách gọi useCounterStore.
function Counter() {
const count = useCounterStore((state) => state.count)
const increment = useCounterStore((state) => state.increment)
return (
<div>
<span>{count}</span>
<button onClick={increment}>Tăng</button>
</div>
)
}
Selector và tối ưu hiệu năng re-render
Một trong những điểm mạnh nhất của Zustand là cơ chế selector. Mỗi component chỉ re-render khi phần state mà nó chọn thay đổi. Ví dụ trên, component Counter chỉ re-render khi count thay đổi, hoàn toàn không bị ảnh hưởng nếu các phần khác trong store thay đổi.
Để so sánh, nếu dùng Context API, mọi component consuming cùng context sẽ re-render khi bất kỳ giá trị nào trong context thay đổi. Zustand tránh được vấn đề này bằng cách sử dụng strict equality comparison (old === new).
Đối với trường hợp cần chọn object hoặc array phức tạp, Zustand cung cấp hook useShallow để so sánh theo shallow equality, tránh re-render không cần thiết:
import { useShallow } from 'zustand/react/shallow'
const { bears, fishes } = useStore(
useShallow((state) => ({ bears: state.bears, fishes: state.fishes }))
)

Middleware mạnh mẽ
Zustand cung cấp hệ thống middleware linh hoạt thông qua zustand/middleware. Đây là nơi thư viện thực sự tỏa sáng so với các đối thủ:
- Persist: Tự động lưu state vào localStorage hoặc sessionStorage. Chỉ cần bọc store với persist middleware, toàn bộ state sẽ được lưu lại ngay cả khi refresh trang.
- Devtools: Tích hợp trực tiếp với Redux DevTools extension, cho phép time-travel debugging mà không cần cấu hình phức tạp.
- Immer: Cho phép viết state update theo kiểu mutable (sử dụng Immer bên dưới), code ngắn hơn đáng kể.
- Redux: Nếu bạn muốn viết theo kiểu reducer-action, Zustand vẫn hỗ trợ thông qua redux middleware.
Ví dụ kết hợp persist và devtools:
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
const useStore = create(
devtools(
persist(
(set, get) => ({
theme: 'light',
setTheme: (theme) => set({ theme }),
}),
{ name: 'app-settings' }
)
)
)
API ngoài component
Zustand không giới hạn bạn trong hệ thống React hooks. Bạn có thể đọc và ghi state từ bất kỳ đâu trong JavaScript thuần, rất hữu ích cho service layers, utility functions, hoặc testing:
// Đọc state
const currentCount = useCounterStore.getState().count
// Ghi state
useCounterStore.setState({ count: 10 })
// Lắng nghe thay đổi
const unsubscribe = useCounterStore.subscribe(
(state) => console.log('State changed:', state)
)
So sánh Zustand với Redux Toolkit và Jotai
| Tiêu chí | Zustand | Redux Toolkit | Jotai |
|---|---|---|---|
| Boilerplate | Rất ít | Trung bình | Rất ít |
| Provider | Không cần | Cần | Cần |
| Mô hình | Flux (1 store) | Flux (1 store) | Atomic (nhiều atom) |
| TypeScript | Hỗ trợ tốt | Hỗ trợ tốt | Hỗ trợ tốt |
| DevTools | Có (middleware) | Có (native) | Có (middleware) |
| Persist | Có (middleware) | Có (redux-persist) | Có (atomWithStorage) |
Jotai và Zustand đều do Daishi Kato tạo ra, nhưng phục vụ mục đích khác nhau: Zustand phù hợp cho flux-style state management (một store tập trung), trong khi Jotai phù hợp cho atomic state (nhiều atom nhỏ riêng biệt, tự động cập nhật).
Khi nào nên và không nên dùng Zustand
- Nên dùng: Ứng dụng trung bình đến lớn cần state dùng chung giữa nhiều component không liên quan. Muốn hiệu năng re-render tối ưu mà không cần cấu hình phức tạp. Cần persist state vào localStorage. Muốn debug dễ dàng với Redux DevTools.
- Không nên dùng: State chỉ dùng trong một component (useState đủ đơn giản). App cần kiến trúc Redux chuẩn với time-travel debugging nghiêm ngặt (Redux Toolkit vẫn tốt hơn). Ứng dụng sử dụng React Server Components (Next.js 13+) — store có thể gây bug và lộ privacy dữ liệu.
Zustand đại diện cho triết lý “ít code hơn, làm được nhiều hơn” trong hệ sinh thái React. Với hơn 50 triệu lượt tải mỗi tuần, đây là một trong những lựa chọn state management phổ biến nhất hiện nay và xứng đáng là lựa chọn đầu tiên cho bất kỳ dự án React nào.
