Zustand 教程
1. 项目概述
Zustand 是一个轻量级的状态管理库,基于简化的 Flux 架构,它提供了一种简单、直观的方式来管理 React 应用的状态。与 Redux 相比,Zustand 更加轻量、简单,并且不需要繁琐的配置。
1.1 主要特性
- 轻量级:核心代码只有几百行,无依赖
- 简单易用:API 简洁明了,学习曲线平缓
- 无需 Provider:不需要在应用顶层包裹 Provider
- 中间件支持:内置持久化、devtools 等中间件
- 订阅机制:可以选择性地订阅状态的一部分
- TypeScript 支持:内置类型定义
- 性能优异:避免不必要的渲染
- 与 React 生态系统集成:支持 React 18 的并发特性
- 可用于非 React 环境:核心逻辑不依赖 React
1.2 适用场景
- 中小型 React 应用
- 需要简单状态管理的项目
- 对性能有要求的应用
- 不希望使用复杂状态管理库的项目
- 需要与其他状态管理库共存的项目
2. 安装与设置
2.1 环境要求
- Node.js 14.0 或更高版本
- npm 或 yarn 包管理器
- React 16.8 或更高版本(支持 Hooks)
2.2 安装步骤
# 使用 npm 安装
npm install zustand
# 使用 yarn 安装
yarn add zustand
# 使用 pnpm 安装
pnpm add zustand2.3 基本项目结构
my-zustand-app/
├── src/
│ ├── store/
│ │ ├── counterStore.js # 计数器状态
│ │ └── userStore.js # 用户状态
│ ├── components/
│ │ ├── Counter.js # 计数器组件
│ │ └── UserProfile.js # 用户信息组件
│ ├── App.js # 根组件
│ └── index.js # 应用入口
├── package.json # 项目配置
└── package-lock.json # 依赖锁定3. 核心概念
3.1 Store
Store 是 Zustand 的核心概念,它是一个包含状态和修改状态方法的对象。
// src/store/counterStore.js
import create from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
incrementByAmount: (amount) => set((state) => ({ count: state.count + amount })),
}));
export default useCounterStore;3.2 Set Function
set 函数是创建 store 时传入的参数,它用于修改状态。set 函数可以接收一个对象或一个函数:
- 对象形式:直接替换状态中的对应属性
- 函数形式:接收当前状态,返回新的状态对象
3.3 Get Function
get 函数用于获取当前状态,它可以在 action 中使用:
const useStore = create((set, get) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
getDoubleCount: () => {
const currentCount = get().count;
return currentCount * 2;
},
}));3.4 订阅
Zustand 提供了订阅机制,允许组件只订阅状态的一部分,从而避免不必要的渲染:
// 订阅整个状态
const count = useCounterStore((state) => state.count);
// 订阅多个状态
const { count, increment } = useCounterStore((state) => ({
count: state.count,
increment: state.increment,
}));3.5 中间件
Zustand 支持中间件,用于扩展 store 的功能:
import { persist, devtools } from 'zustand/middleware';
const useCounterStore = create(
devtools(
persist(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}),
{
name: 'counter-storage', // 存储键名
}
)
)
);4. 基本使用
4.1 创建 Store
基本 store
// src/store/counterStore.js
import { create } from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
export default useCounterStore;带 get 函数的 store
// src/store/userStore.js
import { create } from 'zustand';
const useUserStore = create((set, get) => ({
users: [],
loading: false,
error: null,
addUser: (user) => set((state) => ({
users: [...state.users, user],
})),
removeUser: (userId) => set((state) => ({
users: state.users.filter((user) => user.id !== userId),
})),
updateUser: (userId, updates) => set((state) => ({
users: state.users.map((user) =>
user.id === userId ? { ...user, ...updates } : user
),
})),
getUserById: (userId) => {
const { users } = get();
return users.find((user) => user.id === userId);
},
}));
export default useUserStore;4.2 在组件中使用
基本用法
// src/components/Counter.js
import React from 'react';
import useCounterStore from '../store/counterStore';
function Counter() {
// 订阅状态和方法
const count = useCounterStore((state) => state.count);
const increment = useCounterStore((state) => state.increment);
const decrement = useCounterStore((state) => state.decrement);
const reset = useCounterStore((state) => state.reset);
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
);
}
export default Counter;解构用法
// src/components/UserList.js
import React from 'react';
import useUserStore from '../store/userStore';
function UserList() {
// 一次性订阅多个状态和方法
const { users, addUser, removeUser } = useUserStore((state) => ({
users: state.users,
addUser: state.addUser,
removeUser: state.removeUser,
}));
const handleAddUser = () => {
const newUser = {
id: Date.now(),
name: `User ${Date.now()}`,
email: `user${Date.now()}@example.com`,
};
addUser(newUser);
};
return (
<div>
<h1>User List</h1>
<button onClick={handleAddUser}>Add User</button>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} ({user.email})
<button onClick={() => removeUser(user.id)}>Remove</button>
</li>
))}
</ul>
</div>
);
}
export default UserList;获取整个 store
// src/components/UserProfile.js
import React from 'react';
import useUserStore from '../store/userStore';
function UserProfile({ userId }) {
const userStore = useUserStore();
const user = userStore.getUserById(userId);
if (!user) {
return <div>User not found</div>;
}
return (
<div>
<h2>User Profile</h2>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
);
}
export default UserProfile;4.3 使用中间件
持久化中间件
// src/store/persistStore.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const usePersistStore = create(
persist(
(set) => ({
count: 0,
user: {
name: '',
email: '',
},
increment: () => set((state) => ({ count: state.count + 1 })),
setUser: (user) => set({ user }),
}),
{
name: 'my-app-storage', // 存储在 localStorage 中的键名
// 可以自定义存储方式
// getStorage: () => sessionStorage,
}
)
);
export default usePersistStore;DevTools 中间件
// src/store/devToolsStore.js
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
const useDevToolsStore = create(
devtools(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}),
{
name: 'MyStore', // DevTools 中的名称
}
)
);
export default useDevToolsStore;组合中间件
// src/store/combinedStore.js
import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';
const useCombinedStore = create(
devtools(
persist(
(set) => ({
count: 0,
user: null,
increment: () => set((state) => ({ count: state.count + 1 })),
setUser: (user) => set({ user }),
}),
{
name: 'combined-storage',
}
),
{
name: 'CombinedStore',
}
)
);
export default useCombinedStore;5. 高级功能
5.1 异步 Action
基本异步 action
// src/store/apiStore.js
import { create } from 'zustand';
const useApiStore = create((set) => ({
data: null,
loading: false,
error: null,
fetchData: async () => {
set({ loading: true, error: null });
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await response.json();
set({ data, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
},
}));
export default useApiStore;使用 async/await
// src/store/userApiStore.js
import { create } from 'zustand';
const useUserApiStore = create((set, get) => ({
users: [],
loading: false,
error: null,
fetchUsers: async () => {
set({ loading: true, error: null });
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await response.json();
set({ users, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
},
fetchUserById: async (userId) => {
set({ loading: true, error: null });
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
const user = await response.json();
// 将新用户添加到列表中
set((state) => ({
users: [...state.users.filter(u => u.id !== userId), user],
loading: false,
}));
} catch (error) {
set({ error: error.message, loading: false });
}
},
}));
export default useUserApiStore;5.2 选择器
基本选择器
// src/store/todoStore.js
import { create } from 'zustand';
const useTodoStore = create((set) => ({
todos: [
{ id: 1, text: 'Learn Zustand', completed: true },
{ id: 2, text: 'Build an app', completed: false },
{ id: 3, text: 'Deploy to production', completed: false },
],
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
),
})),
}));
// 选择器
export const selectCompletedTodos = (state) =>
state.todos.filter((todo) => todo.completed);
export const selectIncompleteTodos = (state) =>
state.todos.filter((todo) => !todo.completed);
export const selectTodoById = (id) => (state) =>
state.todos.find((todo) => todo.id === id);
export default useTodoStore;在组件中使用选择器
// src/components/TodoList.js
import React from 'react';
import useTodoStore, { selectCompletedTodos, selectIncompleteTodos } from '../store/todoStore';
function TodoList() {
const todos = useTodoStore((state) => state.todos);
const addTodo = useTodoStore((state) => state.addTodo);
const toggleTodo = useTodoStore((state) => state.toggleTodo);
// 使用选择器
const completedTodos = useTodoStore(selectCompletedTodos);
const incompleteTodos = useTodoStore(selectIncompleteTodos);
const [inputText, setInputText] = React.useState('');
const handleAddTodo = () => {
if (inputText.trim()) {
addTodo(inputText);
setInputText('');
}
};
return (
<div>
<h1>Todo List</h1>
<div>
<input
type="text"
value={inputText}
onChange={(e) => setInputText(e.target.value)}
placeholder="Add a todo"
/>
<button onClick={handleAddTodo}>Add</button>
</div>
<h2>All Todos ({todos.length})</h2>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span style={{
textDecoration: todo.completed ? 'line-through' : 'none',
}}>
{todo.text}
</span>
</li>
))}
</ul>
<h2>Completed Todos ({completedTodos.length})</h2>
<ul>
{completedTodos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
<h2>Incomplete Todos ({incompleteTodos.length})</h2>
<ul>
{incompleteTodos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</div>
);
}
export default TodoList;5.3 模块化 Store
创建多个 store
// src/store/index.js
import useCounterStore from './counterStore';
import useUserStore from './userStore';
import useTodoStore from './todoStore';
export {
useCounterStore,
useUserStore,
useTodoStore,
};在组件中使用多个 store
// src/components/Dashboard.js
import React from 'react';
import { useCounterStore, useUserStore, useTodoStore } from '../store';
function Dashboard() {
// 从不同 store 中获取状态
const count = useCounterStore((state) => state.count);
const userCount = useUserStore((state) => state.users.length);
const todoCount = useTodoStore((state) => state.todos.length);
const completedTodoCount = useTodoStore(
(state) => state.todos.filter((todo) => todo.completed).length
);
return (
<div>
<h1>Dashboard</h1>
<div>
<h2>Counter: {count}</h2>
<h2>Users: {userCount}</h2>
<h2>Todos: {todoCount}</h2>
<h2>Completed Todos: {completedTodoCount}</h2>
</div>
</div>
);
}
export default Dashboard;5.4 自定义中间件
创建自定义中间件
// src/middleware/loggerMiddleware.js
const loggerMiddleware = (config) => (set, get, api) => {
// 保存原始的 set 函数
const originalSet = api.setState;
// 重写 set 函数
api.setState = (...args) => {
console.log('Before state update:', get());
originalSet(...args);
console.log('After state update:', get());
};
// 调用原始配置
return config(set, get, api);
};
export default loggerMiddleware;使用自定义中间件
// src/store/loggerStore.js
import { create } from 'zustand';
import loggerMiddleware from '../middleware/loggerMiddleware';
const useLoggerStore = create(
loggerMiddleware((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}))
);
export default useLoggerStore;5.5 TypeScript 支持
使用 TypeScript 创建 store
// src/store/counterStore.ts
import { create } from 'zustand';
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
incrementByAmount: (amount: number) => void;
}
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 }),
incrementByAmount: (amount) => set((state) => ({ count: state.count + amount })),
}));
export default useCounterStore;复杂类型
// src/store/userStore.ts
import { create } from 'zustand';
interface User {
id: number;
name: string;
email: string;
}
interface UserState {
users: User[];
loading: boolean;
error: string | null;
addUser: (user: Omit<User, 'id'>) => void;
removeUser: (id: number) => void;
updateUser: (id: number, updates: Partial<User>) => void;
fetchUsers: () => Promise<void>;
}
const useUserStore = create<UserState>((set) => ({
users: [],
loading: false,
error: null,
addUser: (user) => set((state) => ({
users: [...state.users, { ...user, id: Date.now() }],
})),
removeUser: (id) => set((state) => ({
users: state.users.filter((user) => user.id !== id),
})),
updateUser: (id, updates) => set((state) => ({
users: state.users.map((user) =>
user.id === id ? { ...user, ...updates } : user
),
})),
fetchUsers: async () => {
set({ loading: true, error: null });
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await response.json();
set({ users, loading: false });
} catch (error) {
set({ error: (error as Error).message, loading: false });
}
},
}));
export default useUserStore;6. 实用案例
6.1 购物车应用
创建购物车 store
// src/store/cartStore.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useCartStore = create(
persist(
(set, get) => ({
items: [],
addToCart: (product) => set((state) => {
const existingItem = state.items.find((item) => item.id === product.id);
if (existingItem) {
return {
items: state.items.map((item) =>
item.id === product.id
? { ...item, quantity: item.quantity + 1 }
: item
),
};
}
return {
items: [...state.items, { ...product, quantity: 1 }],
};
}),
removeFromCart: (productId) => set((state) => ({
items: state.items.filter((item) => item.id !== productId),
})),
updateQuantity: (productId, quantity) => set((state) => ({
items: state.items.map((item) =>
item.id === productId ? { ...item, quantity } : item
),
})),
clearCart: () => set({ items: [] }),
getTotalItems: () => {
const { items } = get();
return items.reduce((total, item) => total + item.quantity, 0);
},
getTotalPrice: () => {
const { items } = get();
return items.reduce((total, item) => total + item.price * item.quantity, 0);
},
}),
{
name: 'cart-storage',
}
)
);
export default useCartStore;创建购物车组件
// src/components/Cart.js
import React from 'react';
import useCartStore from '../store/cartStore';
function Cart() {
const items = useCartStore((state) => state.items);
const removeFromCart = useCartStore((state) => state.removeFromCart);
const updateQuantity = useCartStore((state) => state.updateQuantity);
const clearCart = useCartStore((state) => state.clearCart);
const getTotalItems = useCartStore((state) => state.getTotalItems);
const getTotalPrice = useCartStore((state) => state.getTotalPrice);
const totalItems = getTotalItems();
const totalPrice = getTotalPrice();
if (items.length === 0) {
return <div>Your cart is empty</div>;
}
return (
<div>
<h1>Shopping Cart</h1>
<button onClick={clearCart}>Clear Cart</button>
<h2>Total Items: {totalItems}</h2>
<h2>Total Price: ${totalPrice.toFixed(2)}</h2>
<ul>
{items.map((item) => (
<li key={item.id}>
<h3>{item.name}</h3>
<p>Price: ${item.price.toFixed(2)}</p>
<div>
<button onClick={() => updateQuantity(item.id, Math.max(1, item.quantity - 1))}>-</button>
<span>Quantity: {item.quantity}</span>
<button onClick={() => updateQuantity(item.id, item.quantity + 1)}>+</button>
</div>
<button onClick={() => removeFromCart(item.id)}>Remove</button>
</li>
))}
</ul>
</div>
);
}
export default Cart;创建产品列表组件
// src/components/ProductList.js
import React from 'react';
import useCartStore from '../store/cartStore';
// 模拟产品数据
const products = [
{ id: 1, name: 'Product 1', price: 10.99 },
{ id: 2, name: 'Product 2', price: 19.99 },
{ id: 3, name: 'Product 3', price: 5.99 },
{ id: 4, name: 'Product 4', price: 29.99 },
];
function ProductList() {
const addToCart = useCartStore((state) => state.addToCart);
return (
<div>
<h1>Products</h1>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap' }}>
{products.map((product) => (
<div key={product.id} style={{ border: '1px solid #ccc', padding: '10px', width: '200px' }}>
<h2>{product.name}</h2>
<p>Price: ${product.price.toFixed(2)}</p>
<button onClick={() => addToCart(product)}>Add to Cart</button>
</div>
))}
</div>
</div>
);
}
export default ProductList;6.2 认证状态管理
创建认证 store
// src/store/authStore.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useAuthStore = create(
persist(
(set) => ({
user: null,
token: null,
loading: false,
error: null,
login: async (email, password) => {
set({ loading: true, error: null });
try {
// 模拟登录 API 调用
await new Promise((resolve) => setTimeout(resolve, 1000));
const mockUser = {
id: 1,
name: 'John Doe',
email: email,
};
const mockToken = 'mock-token-123';
set({ user: mockUser, token: mockToken, loading: false });
return true;
} catch (error) {
set({ error: 'Invalid email or password', loading: false });
return false;
}
},
logout: () => set({ user: null, token: null }),
updateUser: (updates) => set((state) => ({
user: state.user ? { ...state.user, ...updates } : null,
})),
}),
{
name: 'auth-storage',
// 只持久化 user 和 token
partialize: (state) => ({ user: state.user, token: state.token }),
}
)
);
export default useAuthStore;创建登录组件
// src/components/Login.js
import React, { useState } from 'react';
import useAuthStore from '../store/authStore';
function Login() {
const login = useAuthStore((state) => state.login);
const loading = useAuthStore((state) => state.loading);
const error = useAuthStore((state) => state.error);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleLogin = async (e) => {
e.preventDefault();
await login(email, password);
};
return (
<div>
<h1>Login</h1>
{error && <p style={{ color: 'red' }}>{error}</p>}
<form onSubmit={handleLogin}>
<div>
<label>Email:</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div>
<label>Password:</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
<button type="submit" disabled={loading}>
{loading ? 'Logging in...' : 'Login'}
</button>
</form>
</div>
);
}
export default Login;创建用户信息组件
// src/components/UserProfile.js
import React from 'react';
import useAuthStore from '../store/authStore';
function UserProfile() {
const user = useAuthStore((state) => state.user);
const logout = useAuthStore((state) => state.logout);
const updateUser = useAuthStore((state) => state.updateUser);
if (!user) {
return <div>Please login to see your profile</div>;
}
return (
<div>
<h1>User Profile</h1>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<button onClick={logout}>Logout</button>
<button onClick={() => updateUser({ name: 'Updated Name' })}>
Update Name
</button>
</div>
);
}
export default UserProfile;7. 性能优化
7.1 选择性订阅
只订阅需要的状态
// 不好的做法:订阅整个状态
const store = useStore(); // 会在任何状态变化时重新渲染
// 好的做法:选择性订阅
const count = useStore((state) => state.count); // 只在 count 变化时重新渲染
const increment = useStore((state) => state.increment); // 函数引用稳定,不会导致重新渲染使用 useShallow 优化对象订阅
// src/components/OptimizedComponent.js
import React from 'react';
import { useShallow } from 'zustand/react/shallow';
import useCounterStore from '../store/counterStore';
function OptimizedComponent() {
// 使用 useShallow 进行浅层比较
const { count, increment, decrement } = useCounterStore(
useShallow((state) => ({
count: state.count,
increment: state.increment,
decrement: state.decrement,
}))
);
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
export default OptimizedComponent;7.2 避免在渲染中创建新函数
不好的做法
// 不好的做法:每次渲染都会创建新的选择器函数
function BadComponent() {
const todos = useTodoStore((state) =>
state.todos.filter((todo) => todo.completed)
);
// ...
}好的做法
// 好的做法:将选择器提取到组件外部
const selectCompletedTodos = (state) =>
state.todos.filter((todo) => todo.completed);
function GoodComponent() {
const todos = useTodoStore(selectCompletedTodos);
// ...
}7.3 使用 memo 包装组件
// src/components/MemoizedComponent.js
import React, { memo } from 'react';
import useCounterStore from '../store/counterStore';
const MemoizedCounter = memo(() => {
const count = useCounterStore((state) => state.count);
console.log('MemoizedCounter rendered');
return <div>Count: {count}</div>;
});
function MemoizedComponent() {
const increment = useCounterStore((state) => state.increment);
return (
<div>
<h1>Memoized Component</h1>
<MemoizedCounter />
<button onClick={increment}>Increment</button>
</div>
);
}
export default MemoizedComponent;8. 最佳实践
8.1 项目结构
- 按功能组织 store:将相关的状态和操作放在一个 store 中
- 使用模块化导出:通过 index.js 导出所有 store
- 分离业务逻辑:将复杂的业务逻辑从组件中移到 store 中
- 使用选择器:创建可重用的选择器函数
8.2 Store 设计
- 保持 store 简洁:每个 store 只负责一个领域的状态
- 使用不可变更新:遵循不可变数据原则
- 提供清晰的 API:为每个操作提供明确的方法
- 处理异步操作:在 store 中处理异步逻辑
- 添加适当的状态:包括 loading、error 等状态
8.3 组件使用
- 选择性订阅:只订阅组件需要的状态
- 使用 useShallow:对于对象和数组的订阅,使用 useShallow 进行优化
- 避免在渲染中创建新函数:将选择器提取到组件外部
- 使用 memo:对于纯展示组件,使用 React.memo 进行优化
8.4 中间件使用
- 使用持久化中间件:对于需要持久化的状态,使用 persist 中间件
- 使用 DevTools 中间件:在开发环境中使用 devtools 中间件
- 创建自定义中间件:对于特定的需求,创建自定义中间件
8.5 测试
- 测试 store 逻辑:测试状态更新和异步操作
- 测试选择器:测试选择器是否正确提取数据
- 测试组件:测试组件与 store 的交互
9. 常见问题与解决方案
9.1 状态不更新
问题:调用 action 后状态没有更新
解决方案:
- 检查 action 是否正确调用
- 确保在 set 函数中返回新的状态对象
- 对于嵌套状态,确保使用不可变更新
9.2 组件不重新渲染
问题:状态更新后组件没有重新渲染
解决方案:
- 检查是否正确订阅了状态
- 确保订阅的状态确实发生了变化
- 对于对象和数组,确保返回新的引用
9.3 持久化不工作
问题:使用 persist 中间件后状态没有持久化
解决方案:
- 检查存储键名是否正确
- 确保浏览器支持 localStorage
- 检查状态是否可序列化
9.4 异步操作错误
问题:异步 action 失败或不执行
解决方案:
- 检查异步函数是否正确使用 async/await
- 确保在异步操作中正确处理错误
- 检查网络请求是否正确
9.5 多个 store 之间的通信
问题:需要在一个 store 中访问另一个 store 的状态
解决方案:
- 将一个 store 的引用传递给另一个 store
- 使用事件系统进行通信
- 将共享状态提取到一个单独的 store 中
10. 参考资源
10.1 官方文档
10.2 学习资源
10.3 工具与库
- Zustand - 核心库
- Zustand DevTools - 调试工具
- Zustand Persist - 持久化中间件
10.4 相关库
11. 总结
Zustand 是一个轻量级、简单易用的状态管理库,它提供了一种直观的方式来管理 React 应用的状态。通过本教程,你应该已经掌握了 Zustand 的基本使用方法和高级功能,包括:
- 核心概念(store、set、get)
- 基本使用
- 中间件(persist、devtools)
- 异步 action
- 选择器
- 模块化 store
- 自定义中间件
- TypeScript 支持
- 性能优化
- 最佳实践
Zustand 的设计理念是 "简单至上",它通过最小化 API 表面和避免不必要的复杂性,为开发者提供了一种简洁、高效的状态管理方案。与其他状态管理库相比,Zustand 具有以下优势:
- 轻量级:核心代码只有几百行,无依赖
- 简单易用:API 简洁明了,学习曲线平缓
- 无需 Provider:不需要在应用顶层包裹 Provider
- 性能优异:避免不必要的渲染
- 灵活多变:支持中间件、选择器等高级功能
Zustand 适合从简单的个人项目到复杂的企业级应用的各种场景。它的灵活性和可扩展性使其成为 React 生态系统中一个重要的状态管理解决方案。
随着你对 Zustand 的深入了解,你会发现它不仅是一个状态管理库,更是一种开发理念:通过简洁的 API 和清晰的架构,让状态管理变得更加简单和可预测。希望本教程对你的学习和开发有所帮助!