Zustand 是一个轻量、无样板代码(boilerplate)的 React 状态管理库。相比 Redux 更简单,相比 Context 更高效,非常适合中小型到中大型项目。
一、Zustand 核心理念
✅ 设计哲学
- 极简 API
- 基于 Hooks
- 无 Provider(默认)
- 支持中间件
- 支持 TS 友好
核心思想:
用一个全局 store + hook 选择性订阅状态
二、基础入门
1️⃣ 安装
bash
npm install zustand2️⃣ 创建第一个 Store
ts
import { create } from 'zustand'
const useCounterStore = create((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
decrease: () => set((state) => ({ count: state.count - 1 })),
}))3️⃣ 组件中使用
tsx
function Counter() {
const { count, increase, decrease } = useCounterStore()
return (
<>
<div>{count}</div>
<button onClick={increase}>+</button>
<button onClick={decrease}>-</button>
</>
)
}- ✔ 自动订阅
- ✔ 组件卸载自动取消订阅
- ✔ 无 Provider
三、进阶核心技巧
🎯 1. 精准订阅(避免无效渲染)
ts
const count = useCounterStore((state) => state.count)只监听 count,其他字段变化不会触发重渲染。
搭配浅比较
ts
import { shallow } from 'zustand/shallow'
const { count, increase } = useCounterStore(
(state) => ({ count: state.count, increase: state.increase }),
shallow
)🎯 2. 异步操作(请求接口)
ts
const useUserStore = create((set) => ({
user: null,
loading: false,
fetchUser: async () => {
set({ loading: true })
const res = await fetch('/api/user')
const data = await res.json()
set({ user: data, loading: false })
}
}))- ✔ Zustand 不限制 async
- ✔ 无 thunk / saga 概念
🎯 3. 中间件使用
persist(本地存储)
ts
import { persist } from 'zustand/middleware'
const useStore = create(
persist(
(set) => ({
theme: 'light',
toggle: () => set((s) => ({ theme: s.theme === 'light' ? 'dark' : 'light' })),
}),
{
name: 'app-storage',
}
)
)devtools(调试)
ts
import { devtools } from 'zustand/middleware'
const useStore = create(
devtools((set) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 }), false, 'inc')
}))
)可在 Redux DevTools 中查看。
🎯 4. 拆分模块(大型项目)
推荐结构:
store/
├── index.ts
├── user.ts
├── cart.ts
└── theme.ts模块合并
ts
import { create } from 'zustand'
import { createUserSlice } from './user'
import { createCartSlice } from './cart'
export const useStore = create((...a) => ({
...createUserSlice(...a),
...createCartSlice(...a),
}))- ✔ 类似 Redux slice
- ✔ 更清晰
- ✔ 可维护性强
四、高级实战技巧
🔥 1. get() 读取最新状态
ts
const useStore = create((set, get) => ({
count: 0,
double: () => {
const current = get().count
set({ count: current * 2 })
}
}))🔥 2. subscribe 监听(非组件环境)
ts
const unsubscribe = useStore.subscribe(
(state) => state.count,
(count) => console.log('count changed:', count)
)适用于:
- 日志系统
- websocket
- 外部模块监听
🔥 3. immer 中间件(复杂对象)
ts
import { immer } from 'zustand/middleware/immer'
const useStore = create(
immer((set) => ({
user: { name: '', age: 0 },
updateName: (name: string) =>
set((state) => {
state.user.name = name
}),
}))
)- ✔ 可变写法
- ✔ 内部自动 immutable
🔥 4. 重置 Store
ts
const initialState = { count: 0 }
const useStore = create((set) => ({
...initialState,
reset: () => set(initialState),
}))五、性能优化总结
✅ 必做
- 使用 selector
- 使用 shallow
- 拆分 store
- 避免大对象直接返回
❌ 避免
- 整个 state 解构
- 在 store 里写复杂 UI 状态
- 所有状态放一个 store
六、Zustand vs Redux 对比
| 对比 | Zustand | Redux |
|---|---|---|
| 学习成本 | 低 | 高 |
| 模板代码 | 少 | 多 |
| 中间件 | 支持 | 强 |
| 适合项目 | 中小/中大型 | 中大型 |
七、企业级最佳实践
1️⃣ 状态分层
- UI状态(本地)
- 全局共享状态(Zustand)
- 服务器状态(React Query)
推荐组合:
- Zustand + React Query
- Zustand + Vite
- Zustand + Next.js
2️⃣ 不要滥用全局状态
判断标准:
- 多组件共享?
- 是否跨页面?
- 是否需要缓存?
否则使用 useState。
八、常见坑总结
- ⚠ StrictMode 下初始化两次
- ⚠ persist 需要处理版本升级
- ⚠ SSR 需避免状态污染
- ⚠ 异步并发注意覆盖问题
九、实战项目结构示例
src/
├── store/
│ ├── authStore.ts
│ ├── productStore.ts
│ └── index.ts
├── hooks/
├── pages/
└── services/🔟 终极总结
Zustand 适合:
- ✔ 追求简单
- ✔ 不想写 reducer
- ✔ 不想配置复杂中间件
- ✔ 希望极致开发体验
一句话总结:
小而美,够用且强大。