Zustand 状态管理教程
学习使用 Zustand 进行简洁高效的 React 状态管理,掌握现代状态管理的最佳实践
为什么选择 Zustand?
Zustand 是一个轻量级的 React 状态管理库,提供了简洁的 API 和强大的功能。 相比 Redux,它有更少的样板代码;相比 Context API,它有更好的性能。
简洁 API
最少的样板代码,直观易用
高性能
选择性订阅,避免不必要的重渲染
灵活扩展
丰富的中间件生态系统
基础 Store 创建
Zustand 的核心是 create 函数,它接受一个函数并返回一个 hook。 这个函数接收 set 和 get 参数来管理状态。
基础 Store 示例
// stores/useCounterStore.ts
import { create } from 'zustand';
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
// 在组件中使用
function Counter() {
const { count, increment, decrement, reset } = useCounterStore();
return (
<div>
<p>计数: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>重置</button>
</div>
);
}
简单状态管理演示
体验 Zustand 管理基本状态,包括计数器和待办事项列表
简单计数器状态
0
待办事项列表状态
学习 Zustand
构建状态管理
总共 2 项,已完成 1 项
高级 Store 设计
高级 Store 可以包含复杂的状态结构、计算属性、中间件支持等。 通过合理的设计,可以构建出功能强大且易于维护的状态管理系统。
高级 Store 设计
// stores/useAppStore.ts
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
import { persist, createJSONStorage } from 'zustand/middleware';
interface User {
id: number;
name: string;
email: string;
}
interface Todo {
id: number;
text: string;
completed: boolean;
createdAt: Date;
}
interface AppState {
// 用户状态
user: User | null;
setUser: (user: User | null) => void;
// 待办事项状态
todos: Todo[];
addTodo: (text: string) => void;
toggleTodo: (id: number) => void;
deleteTodo: (id: number) => void;
clearCompleted: () => void;
// UI 状态
isLoading: boolean;
setLoading: (loading: boolean) => void;
// 主题状态
theme: 'light' | 'dark';
toggleTheme: () => void;
// 计算属性
completedTodos: Todo[];
pendingTodos: Todo[];
todoStats: {
total: number;
completed: number;
pending: number;
};
}
export const useAppStore = create<AppState>()(
subscribeWithSelector(
persist(
(set, get) => ({
// 初始状态
user: null,
todos: [],
isLoading: false,
theme: 'light',
// 用户相关操作
setUser: (user) => set({ user }),
// 待办事项操作
addTodo: (text) => set((state) => ({
todos: [
...state.todos,
{
id: Date.now(),
text,
completed: false,
createdAt: new Date(),
},
],
})),
toggleTodo: (id) => set((state) => ({
todos: state.todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
deleteTodo: (id) => set((state) => ({
todos: state.todos.filter(todo => todo.id !== id),
})),
clearCompleted: () => set((state) => ({
todos: state.todos.filter(todo => !todo.completed),
})),
// UI 状态操作
setLoading: (isLoading) => set({ isLoading }),
// 主题操作
toggleTheme: () => set((state) => ({
theme: state.theme === 'light' ? 'dark' : 'light',
})),
// 计算属性(getters)
get completedTodos() {
return get().todos.filter(todo => todo.completed);
},
get pendingTodos() {
return get().todos.filter(todo => !todo.completed);
},
get todoStats() {
const todos = get().todos;
return {
total: todos.length,
completed: todos.filter(t => t.completed).length,
pending: todos.filter(t => !t.completed).length,
};
},
}),
{
name: 'app-store', // 本地存储的键名
storage: createJSONStorage(() => localStorage),
// 只持久化特定字段
partialize: (state) => ({
user: state.user,
todos: state.todos,
theme: state.theme,
}),
}
)
)
);
复杂状态管理演示
展示 Zustand 处理复杂应用状态,包括用户、购物车、通知等多个状态模块
用户状态
张三
zhangsan@example.com
购物车状态 (3 件商品)
MacBook Pro
¥12,999
1
iPhone 15
¥5,999
2
总计:¥24,997
通知状态 (2)
欢迎使用 Zustand!
10:30:00
购物车已更新
10:25:00
中间件使用
Zustand 提供了丰富的中间件来扩展功能,包括持久化、订阅、 日志记录、Redux DevTools 集成等。
中间件使用示例
// 中间件使用示例
// 1. 持久化中间件
import { persist, createJSONStorage } from 'zustand/middleware';
const usePersistentStore = create(
persist(
(set) => ({
data: null,
setData: (data) => set({ data }),
}),
{
name: 'persistent-store',
storage: createJSONStorage(() => localStorage),
// 自定义序列化
serialize: (state) => JSON.stringify(state),
deserialize: (str) => JSON.parse(str),
// 版本控制和迁移
version: 1,
migrate: (persistedState, version) => {
if (version === 0) {
// 从版本 0 迁移到版本 1
return { ...persistedState, newField: 'default' };
}
return persistedState;
},
}
)
);
// 2. 订阅中间件
import { subscribeWithSelector } from 'zustand/middleware';
const useSubscriptionStore = create(
subscribeWithSelector((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}))
);
// 订阅特定字段变化
useSubscriptionStore.subscribe(
(state) => state.count,
(count, prevCount) => {
console.log('计数从', prevCount, '变为', count);
}
);
// 3. 日志中间件
const logger = (config) => (set, get, api) =>
config(
(...args) => {
console.log('State before:', get());
set(...args);
console.log('State after:', get());
},
get,
api
);
const useLoggedStore = create(
logger((set) => ({
data: null,
setData: (data) => set({ data }),
}))
);
// 4. Redux DevTools 中间件
import { devtools } from 'zustand/middleware';
const useDevtoolsStore = create(
devtools(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 }), undefined, 'increment'),
decrement: () => set((state) => ({ count: state.count - 1 }), undefined, 'decrement'),
}),
{
name: 'counter-store',
}
)
);
在组件中使用
在 React 组件中使用 Zustand Store 非常简单,支持选择性订阅、 异步操作等高级用法。
组件中使用 Zustand
// 在组件中使用 Zustand
// 1. 基本使用
function TodoList() {
const { todos, addTodo, toggleTodo, deleteTodo } = useAppStore();
const [newTodo, setNewTodo] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (newTodo.trim()) {
addTodo(newTodo);
setNewTodo('');
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
value={newTodo}
onChange={(e) => setNewTodo(e.target.value)}
placeholder="添加待办事项"
/>
<button type="submit">添加</button>
</form>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => deleteTodo(todo.id)}>删除</button>
</li>
))}
</ul>
</div>
);
}
// 2. 选择性订阅(避免不必要的重渲染)
function TodoStats() {
// 只订阅 todoStats,其他状态变化不会触发重渲染
const stats = useAppStore((state) => state.todoStats);
return (
<div>
<p>总计: {stats.total}</p>
<p>已完成: {stats.completed}</p>
<p>待完成: {stats.pending}</p>
</div>
);
}
// 3. 使用 shallow 比较
import { shallow } from 'zustand/shallow';
function UserProfile() {
const { user, setUser } = useAppStore(
(state) => ({ user: state.user, setUser: state.setUser }),
shallow
);
if (!user) return <div>请登录</div>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
// 4. 异步操作
function DataFetcher() {
const { setLoading, setUser } = useAppStore();
const fetchUser = async () => {
setLoading(true);
try {
const response = await fetch('/api/user');
const user = await response.json();
setUser(user);
} catch (error) {
console.error('获取用户失败:', error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchUser();
}, []);
const isLoading = useAppStore((state) => state.isLoading);
if (isLoading) return <div>加载中...</div>;
return <UserProfile />;
}
最佳实践
遵循最佳实践可以让你的 Zustand 应用更加健壮、可维护和高性能。
Zustand 最佳实践
// Zustand 最佳实践
// 1. 按功能分割 Store
// stores/useAuthStore.ts
export const useAuthStore = create<AuthState>((set, get) => ({
user: null,
token: null,
login: async (credentials) => {
const response = await authAPI.login(credentials);
set({ user: response.user, token: response.token });
},
logout: () => set({ user: null, token: null }),
}));
// stores/useCartStore.ts
export const useCartStore = create<CartState>((set, get) => ({
items: [],
addItem: (item) => set((state) => ({
items: [...state.items, item]
})),
removeItem: (id) => set((state) => ({
items: state.items.filter(item => item.id !== id)
})),
}));
// 2. 使用 Immer 处理复杂状态
import { produce } from 'immer';
const useComplexStore = create((set) => ({
nested: {
deeply: {
nested: {
value: 0
}
}
},
updateNested: (newValue) => set(produce((state) => {
state.nested.deeply.nested.value = newValue;
})),
}));
// 3. 类型安全的 Slice 模式
interface UserSlice {
user: User | null;
setUser: (user: User | null) => void;
}
interface TodoSlice {
todos: Todo[];
addTodo: (text: string) => void;
}
const createUserSlice: StateCreator<UserSlice & TodoSlice, [], [], UserSlice> = (set) => ({
user: null,
setUser: (user) => set({ user }),
});
const createTodoSlice: StateCreator<UserSlice & TodoSlice, [], [], TodoSlice> = (set) => ({
todos: [],
addTodo: (text) => set((state) => ({
todos: [...state.todos, { id: Date.now(), text, completed: false }],
})),
});
export const useAppStore = create<UserSlice & TodoSlice>()((...a) => ({
...createUserSlice(...a),
...createTodoSlice(...a),
}));
// 4. Store 重置功能
interface StoreState {
data: any[];
user: User | null;
reset: () => void;
}
const initialState = {
data: [],
user: null,
};
export const useResetableStore = create<StoreState>((set) => ({
...initialState,
reset: () => set(initialState),
}));
// 5. 外部 Store 访问
// 在组件外部访问 store
export const getStoreValue = () => useAppStore.getState();
export const subscribeToStore = (listener) => useAppStore.subscribe(listener);
// 在非 React 环境中使用
async function externalFunction() {
const { user } = useAppStore.getState();
if (user) {
// 执行需要用户登录的操作
await performUserAction();
}
}
Zustand 练习场
尝试创建自己的 Zustand Store,体验状态管理的强大功能:
Zustand 状态管理练习
加载编辑器中...
Zustand vs 其他状态管理
Zustand
- • 极简 API,学习成本低
- • 无需 Provider 包装
- • 支持选择性订阅
- • TypeScript 友好
- • 轻量级 (2.9kb)
Redux Toolkit
- • 强大的生态系统
- • 时间旅行调试
- • 严格的不可变性
- • 复杂的样板代码
- • 较大的包体积
Context API
- • React 内置
- • 适合简单状态
- • 需要多个 Provider
- • 性能问题
- • 复杂状态难以管理
恭喜你完成了所有教程!
通过这个完整的 Next.js 15 教程系列,你已经掌握了现代前端开发的核心技能。 从 Next.js 基础到 TypeScript、数据库操作、缓存、文件存储和状态管理, 你现在可以构建功能完整的现代 Web 应用了。