当你的 React 项目开始“通货膨胀”,是时候请出 Zustand 这位央行行长了!
💡 引子:为什么前端也需要“中央银行”?
想象一下,你正在开发一个 Todo 应用。一开始,状态少得可怜——一个 count、一个 todos 列表,组件之间传传 props 就搞定了。
但随着业务扩张,你的应用开始“经济过热”:
- 用户登录状态要全局共享
- 购物车数据要在多个页面同步
- 深色/浅色主题切换要实时生效
- 网络请求的 loading 状态要统一管理
很快,你的组件树变成了“状态走私网络”:props 一层层往下传,回调函数一层层往上冒,代码像意大利面条一样缠在一起。
这时候,你就需要一个 中央状态管理系统 —— 就像国家需要中央银行来统一发行货币、调控经济一样。
而在 React 的世界里,Zustand 就是那位低调、高效、不搞复杂仪式感的“央行行长”。
🐻 为什么是 Zustand?而不是 Redux?
Redux 很强大,但它有点像“美联储”——规则多、流程繁、仪式感强:
- 必须写 action、reducer、store
- middleware 配置像填税务申报表
- TypeScript 支持虽好,但类型推导常让人头秃
而 Zustand 呢?它更像一个“极简主义央行”:
✅ 基于 Hooks,天然拥抱 React 函数式思维
✅ 一行代码创建 store,无需样板代码
✅ 内置 TypeScript 支持,类型推导丝滑如德芙
✅ 自带 persist 中间件,状态持久化只需两行
✅ 轻量(< 1KB gzipped),性能优异
“Zustand” 在德语中意为 “状态” —— 它不玩花哨,只专注一件事:管理状态。
🛠️ 实战:用 TypeScript + Zustand 打造“三权分立”状态体系
我们以一个典型的前端项目为例,拆解三个核心状态模块:
1️⃣ 计数器 Store:最简单的“货币政策”
// store/counter.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
export const useCounterStore = create<CounterState>()(
persist(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}),
{ name: 'counter' } // 自动存入 localStorage
)
);
💡
persist是 Zustand 官方中间件,自动帮你把状态存到localStorage,刷新不丢失!比手写useEffect + JSON.parse高到不知道哪里去了。
2️⃣ Todo Store:带业务逻辑的“财政系统”
// store/todo.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { Todo } from '../types';
interface TodoState {
todos: Todo[];
addTodo: (text: string) => void;
toggleTodo: (id: number) => void;
removeTodo: (id: number) => void;
}
export const useTodoStore = create<TodoState>()(
persist(
(set) => ({
todos: [],
addTodo: (text) =>
set((state) => ({
todos: [
...state.todos,
{ id: Date.now(), text, completed: false }
]
})),
toggleTodo: (id) =>
set((state) => ({
todos: state.todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
})),
removeTodo: (id) =>
set((state) => ({
todos: state.todos.filter(todo => todo.id !== id)
}))
}),
{ name: 'todos' }
)
);
✨ 注意:这里
id: Date.now()虽然简单,但在高并发场景下可能重复。生产环境建议用crypto.randomUUID()或nanoid。
3️⃣ 用户 Store:安全敏感的“央行金库”
// store/user.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { User } from '../types';
interface UserState {
isLoggedIn: boolean;
user: User | null;
login: (credentials: { username: string; password: string }) => void;
logout: () => void;
}
export const useUserStore = create<UserState>()(
persist(
(set) => ({
isLoggedIn: false,
user: null,
login: ({ username, password }) => {
// TODO: 调用 API 验证
if (password === '123456') {
set({
isLoggedIn: true,
user: { id: 1, username, avatar: '/avatar.jpg' }
});
}
},
logout: () => set({ isLoggedIn: false, user: null })
}),
{
name: 'user',
// 可选:自定义序列化,避免存入敏感信息
// serialize: (state) => JSON.stringify({ ...state, password: undefined })
}
)
);
🔒 安全提示:永远不要在客户端存储密码!
persist默认会序列化整个 state,记得过滤敏感字段。
🎯 在组件中使用:像呼吸一样自然
// App.tsx
import { useCounterStore } from './store/counter';
import { useTodoStore } from './store/todo';
function App() {
const { count, increment, decrement } = useCounterStore();
const { todos, addTodo } = useTodoStore();
return (
<div>
<button onClick={increment}>Count: {count}</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</div>
);
}
🌟 Zustand 的魔法:每个
useStore()只订阅它用到的状态!
即使todos变化,count组件也不会 re-render —— 自动优化,无需memo!
🤔 思考:Zustand 是银弹吗?
当然不是。但它解决了 90% 的状态管理问题,而且学习成本极低。
| 场景 | 推荐方案 |
|---|---|
| 简单全局状态(主题、用户) | ✅ Zustand |
| 复杂数据流(金融交易系统) | ⚠️ 考虑 Redux + RTK |
| 服务端状态(API 数据) | 🔄 React Query / SWR |
| 跨应用通信 | 🌐 BroadcastChannel / Custom Events |
Zustand 不是取代 Redux,而是让大多数项目不再需要 Redux。
🎁 彩蛋:Zustand 的隐藏技能
1. 组合 Store
const useCombinedStore = () => ({
...useCounterStore(),
...useTodoStore()
});
2. 异步 Action
fetchTodos: async () => {
const todos = await api.getTodos();
set({ todos });
}
3. DevTools 支持
import { devtools } from 'zustand/middleware';
create(devtools(...))
→ 自动接入 Redux DevTools,时间旅行调试!
✅ 结语:少即是多,简单即强大
Zustand 的哲学很简单:
“不要为了管理状态,而让代码变得难以管理。”
它没有复杂的概念,没有强制的模式,只有:
- 一个
create - 一个
set - 一堆 TypeScript 类型
却能让你的前端项目状态清晰、逻辑集中、扩展无忧。
所以,下次当你的 React 项目开始“状态通胀”时,别急着引入重型框架——
先问问自己:我是不是只需要一位像 Zustand 这样高效的“央行行长”?