07. Zustand 中间件与最佳实践
一、5W1H 概述
| What | 使用 persist、devtools 等中间件扩展 Zustand |
| Why | 实现状态持久化、调试支持 |
| When | 需要本地存储、Redux DevTools 调试时 |
| Where | store 创建时包裹中间件 |
| Who | 需要高级功能的开发者 |
| How | create(persist(…, { name: 'storage' })) |
二、What – 什么是中间件?
中间件是 Zustand 提供的扩展功能,可以增强 store 的能力。
常用中间件
| persist | 状态持久化到 localStorage/sessionStorage |
| devtools | Redux DevTools 调试支持 |
| immer | 简化不可变更新 |
| subscribeWithSelector | 支持选择器订阅 |
| combine | 合并多个 store |
三、Why – 为什么需要中间件?
3.1 持久化
刷新页面后保持状态(用户登录、主题设置等)。
3.2 调试
使用 Redux DevTools 查看状态变化、时间旅行调试。
3.3 简化代码
Immer 中间件简化嵌套状态更新。
四、When – 何时使用?
| 需要本地存储 | persist |
| 需要调试 | devtools |
| 复杂嵌套更新 | immer |
| 生产环境 | 组合使用 |
五、Where – 在哪里使用?
import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';
const useStore = create(
devtools(
persist(
(set) => ({
// store 定义
}),
{ name: 'storage-key' }
)
)
);
六、Who – 谁需要使用?
需要持久化存储或调试支持的开发者。
七、How – 如何使用中间件?
7.1 persist 中间件
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useStore = create(
persist(
(set) => ({
count: 0,
user: null,
theme: 'light',
increment: () => set((state) => ({ count: state.count + 1 })),
setUser: (user) => set({ user }),
setTheme: (theme) => set({ theme })
}),
{
name: 'app-storage', // localStorage key
getStorage: () => localStorage, // 默认 localStorage
}
)
);
7.2 部分持久化
const useStore = create(
persist(
(set) => ({
count: 0,
temp: '不持久化',
user: null,
increment: () => set((state) => ({ count: state.count + 1 })),
setTemp: (temp) => set({ temp })
}),
{
name: 'app-storage',
// 只持久化 count 和 user
partialize: (state) => ({ count: state.count, user: state.user })
}
)
);
7.3 使用 sessionStorage
const useStore = create(
persist(
(set) => ({
sessionData: null,
setSessionData: (data) => set({ sessionData: data })
}),
{
name: 'session-storage',
getStorage: () => sessionStorage,
}
)
);
7.4 自定义存储
const useStore = create(
persist(
(set) => ({ … }),
{
name: 'custom-storage',
getStorage: () => ({
getItem: (key) => {
const value = localStorage.getItem(key);
console.log('读取:', key, value);
return value;
},
setItem: (key, value) => {
console.log('保存:', key, value);
localStorage.setItem(key, value);
},
removeItem: (key) => {
console.log('删除:', key);
localStorage.removeItem(key);
},
}),
}
)
);
7.5 版本控制
const useStore = create(
persist(
(set) => ({
version: 2,
data: { oldField: 'value', newField: '' }
}),
{
name: 'app-storage',
version: 2,
migrate: (persistedState, version) => {
if (version === 1) {
// 迁移逻辑
return {
…persistedState,
newField: persistedState.oldField || ''
};
}
return persistedState;
},
}
)
);
7.6 devtools 中间件
import { devtools } from 'zustand/middleware';
const useStore = create(
devtools(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 }), false, 'increment'),
decrement: () => set((state) => ({ count: state.count – 1 }), false, 'decrement'),
reset: () => set({ count: 0 }, false, 'reset')
}),
{ name: 'CounterStore' }
)
);
7.7 immer 中间件
npm install immer
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
const useStore = create(
immer((set) => ({
user: {
profile: { name: '张三', age: 25 },
settings: { theme: 'light', notifications: true }
},
todos: [],
// 直接修改,immer 处理不可变性
updateProfileName: (name) =>
set((state) => {
state.user.profile.name = name;
}),
updateSettings: (settings) =>
set((state) => {
Object.assign(state.user.settings, settings);
}),
addTodo: (text) =>
set((state) => {
state.todos.push({ id: Date.now(), text, completed: false });
}),
toggleTodo: (id) =>
set((state) => {
const todo = state.todos.find(t => t.id === id);
if (todo) todo.completed = !todo.completed;
})
}))
);
7.8 组合多个中间件
import { create } from 'zustand';
import { persist, devtools, immer } from 'zustand/middleware';
const useStore = create(
devtools(
persist(
immer((set) => ({
user: null,
token: null,
theme: 'light',
login: async (email, password) =>
set((state) => {
// 使用 immer 直接修改
state.loading = true;
}),
setTheme: (theme) =>
set((state) => {
state.theme = theme;
}),
logout: () =>
set((state) => {
state.user = null;
state.token = null;
})
})),
{ name: 'auth-storage' }
),
{ name: 'AuthStore' }
)
);
八、最佳实践
8.1 Store 拆分
// stores/userStore.js
export const useUserStore = create((set) => ({
user: null,
setUser: (user) => set({ user })
}));
// stores/cartStore.js
export const useCartStore = create((set) => ({
items: [],
addItem: (item) => set((state) => ({ items: […state.items, item] }))
}));
// stores/themeStore.js
export const useThemeStore = create(
persist(
(set) => ({
theme: 'light',
toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' }))
}),
{ name: 'theme-storage' }
)
);
8.2 导出选择器 Hook
const useStore = create(…);
// 导出自定义选择器
export const useCount = () => useStore(state => state.count);
export const useIncrement = () => useStore(state => state.increment);
export const useDecrement = () => useStore(state => state.decrement);
// 使用
function Component() {
const count = useCount();
const increment = useIncrement();
// …
}
8.3 重置 Store
const initialState = { count: 0, user: null, todos: [] };
const useStore = create((set) => ({
…initialState,
reset: () => set(initialState),
increment: () => set((state) => ({ count: state.count + 1 })),
setUser: (user) => set({ user }),
addTodo: (text) => set((state) => ({
todos: […state.todos, { id: Date.now(), text }]
}))
}));
8.4 类型安全(TypeScript)
interface User {
id: number;
name: string;
}
interface UserState {
user: User | null;
setUser: (user: User | null) => void;
}
const useUserStore = create<UserState>()(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user })
}),
{ name: 'user-storage' }
)
);
8.5 条件持久化
const useStore = create(
persist(
(set) => ({
user: null,
rememberMe: false
}),
{
name: 'auth-storage',
// 只有勾选"记住我"时才持久化
partialize: (state) => state.rememberMe ? { user: state.user } : {}
}
)
);
九、练习题
十、小结
| persist | 持久化存储 | { name: 'key' } |
| devtools | 调试支持 | { name: 'StoreName' } |
| immer | 简化更新 | 直接修改状态 |
| 组合使用 | 多中间件叠加 | 嵌套包裹 |


