Zustand 状态管理最佳实践
Created on
前言
Zustand 轻量、自由,但自由意味着需要更强的工程纪律。本文从结构设计、性能订阅、异步治理与可测试性几个维度总结实践要点。
1. 只管理真正的全局状态
跨页面或多组件共享的状态适合放在 store,如用户信息、购物车、权限、主题。组件局部 UI(输入框、折叠、临时弹窗)仍然建议用 useState。
2. 按领域拆分 store
避免单一巨型 store,按业务域拆分能降低耦合、提升可维护性。
authStore: 认证与用户信息cartStore: 购物车与结算uiStore: 全局 UI 状态
3. state 结构保持扁平
深层嵌套会导致更新复杂、选择器冗长。优先扁平化结构,必要时使用 id 映射。
type UserMap = Record<string, User>;
4. selector 驱动渲染
避免直接使用 useStore() 读取整个 state,使用 selector 精确订阅。
const user = useAuthStore((s) => s.user);
多个字段时配合 shallow 减少重渲染:
import { shallow } from "zustand/shallow";
const { user, isLoading } = useAuthStore(
(s) => ({ user: s.user, isLoading: s.isLoading }),
shallow
);
5. actions 承载业务逻辑
组件只调用 action,业务流程集中在 store 内部,更易维护与测试。
const useAuthStore = create<AuthState>((set) => ({
user: null,
isLoading: false,
login: async (params) => {
set({ isLoading: true });
const user = await api.login(params);
set({ user, isLoading: false });
},
}));
6. 异步状态集中治理
统一维护 loading/error 避免散落在组件。
type AuthState = {
user: User | null;
isLoading: boolean;
error: string | null;
};
7. action 避免读取外部可变数据
不要在 action 内部直接读取外部可变变量,通过参数传递保证可预测性。
login: async (email, password) => {
const user = await api.login({ email, password });
set({ user });
};
8. subscribeWithSelector 做副作用
当需要在状态变化时执行副作用(如写入缓存),用订阅替代组件内监听。
const useStore = create(
subscribeWithSelector((set) => ({
token: null,
setToken: (token) => set({ token }),
}))
);
useStore.subscribe(
(s) => s.token,
(token) => {
if (token) localStorage.setItem("token", token);
}
);
9. 持久化克制使用
persist 只保存必要字段,避免存大型对象或敏感信息。
persist((set) => ({ token: null, setToken: (t) => set({ token: t }) }), {
name: "auth",
partialize: (s) => ({ token: s.token }),
});
10. immer 降低复杂更新成本
嵌套数据更新复杂时,使用 zustand/middleware/immer 提升可读性。
import { immer } from "zustand/middleware/immer";
const useStore = create(
immer((set) => ({
todos: [],
toggle: (id) =>
set((s) => {
const item = s.todos.find((t) => t.id === id);
if (item) item.done = !item.done;
}),
}))
);
11. action 设计可测试
请求层抽离,action 接收依赖,测试时可 mock。
login: async (params, api = authApi) => {
const user = await api.login(params);
set({ user });
};
12. 避免过度动态化
不要为了灵活在运行期动态创建过多 store,会削弱可追踪性。多数情况下静态定义 + 按需组合更可靠。
结语
Zustand 的关键在于边界与纪律。控制 store 范围、合理拆分、精确订阅、集中 action 逻辑,就能构建稳定可维护的状态体系。