安装与快速开始
Zustand 是一个轻量、快速、可扩展的 React 状态管理库。它基于发布-订阅模式,API 极其简洁,无需 Provider 包裹,选择器机制天然避免无效重渲染。
前置条件
- React:16.8+(需支持 Hooks)
- Node.js:16.0 或更高版本
- TypeScript:可选,但 Zustand 对 TS 支持极好,推荐使用
Zustand 本身不依赖 React——它的 vanilla API 可在任何 JS 环境中使用(浏览器、Node.js、React Native 等)。
安装
npm install zustand
# 或
yarn add zustand
# 或
pnpm add zustand包体积极小:~2KB gzipped(v4),v5 约 ~1.1KB gzipped。
版本说明
| 版本 | 重大变化 | 推荐 |
|---|---|---|
| v5.x | 移除 default 导出(需命名导入 create);persist 和 subscribeWithSelector 不再默认导出;中间件能力内聚优化 |
✅ 新项目推荐 |
| v4.x | 完善的 TypeScript 支持、useShallow 稳定 |
存量项目维护 |
| v3.x | 早期版本,API 差异大 | ❌ 不再推荐 |
🚨 陷阱:v5 起
import create from 'zustand'失效,必须import { create } from 'zustand'。persist、devtools、subscribeWithSelector也需从具名导出导入。
第一个 Store
import { create } from 'zustand';
// 1. 定义 Store 类型(推荐)
interface BearStore {
bears: number;
increase: () => void;
reset: () => void;
}
// 2. 创建 Store
const useBearStore = create<BearStore>((set) => ({
bears: 0,
increase: () => set((state) => ({ bears: state.bears + 1 })),
reset: () => set({ bears: 0 }),
}));在组件中使用
function BearCounter() {
// 使用选择器精确订阅 bears 字段
const bears = useBearStore((state) => state.bears);
return <h1>{bears} bears around here...</h1>;
}
function Controls() {
// 订阅 action(action 引用不变,不会触发不必要的重渲染)
const increase = useBearStore((state) => state.increase);
return <button onClick={increase}>Add a bear</button>;
}✅ 关键点:无需 Provider! 组件直接通过 useBearStore 订阅状态,这是 Zustand 和 Redux 最大的体验差异。
三秒速览:与 Redux 对比
| 特性 | Zustand | Redux Toolkit |
|---|---|---|
| Provider 包裹 | ❌ 不需要 | ✅ 必须 |
| 创建 Store | create((set) => ({...})) |
configureStore({reducer: {...}}) |
| 读取状态 | useStore(s => s.field) |
useSelector(s => s.field) |
| 修改状态 | set({ field: val }) |
dispatch(action) |
| 不可变更新 | 手动(或配合 Immer) | 内置 Immer |
| 异步 | 在 action 里直接写 async | createAsyncThunk |
| 包体积 | ~2KB | ~11KB |
| DevTools | devtools 中间件 |
内置 |
| 学习曲线 | 极低 | 中 |
项目结构建议
src/
├── stores/
│ ├── useBearStore.ts # 一个 Store 一个文件
│ ├── useUserStore.ts
│ └── useCartStore.ts
├── components/
│ └── ...Zustand 推崇多 Store 模式——按功能域拆分,而不是像 Redux 那样把所有状态塞进单一 Store。每个 Store 文件通常导出以 use 开头的 hook:
// stores/useUserStore.ts
import { create } from 'zustand';
interface UserState {
user: User | null;
setUser: (user: User) => void;
logout: () => void;
}
export const useUserStore = create<UserState>((set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}));💡 最佳实践:Store 文件命名以
use开头(useXxxStore),与 React Hook 命名规范一致,代码阅读时一眼就能认出这是一个 Zustand Store。
在组件外使用
Zustand Store 本身就是发布-订阅对象,可以在任何地方读/写:
// ✅ 在 React 组件外
useBearStore.getState().increase(); // 读取状态
useBearStore.setState({ bears: 10 }); // 直接设置
// ✅ 在普通函数中
function saveToServer() {
const { bears } = useBearStore.getState();
fetch('/api/bears', { method: 'POST', body: JSON.stringify({ bears }) });
}💡 最佳实践:这一特性让 Zustand 天然适合作为事件总线使用——比如在 WebSocket 回调、定时器、fetch 拦截器中直接操作 Store。
快速检查清单
- 安装成功:
npm ls zustand能看到版本号 - 创建了第一个 Store,能在组件中读取和修改状态
- 理解
create、set、get三个核心 API - 理解选择器
useStore(s => s.field)的写法 - 知道在组件外可以用
useStore.getState()/useStore.setState() - TypeScript 类型已正确定义