引言
在React生态系统中,状态管理一直是一个热门话题。从最初的React Context到Redux,再到后来的MobX、Recoil等,开发者们一直在寻找更高效、更简洁的状态管理方案。今天我要介绍的Zustand(德语中意为"状态")就是一个近年来备受关注的轻量级状态管理解决方案。
什么是Zustand?
Zustand是一个小型、快速且可扩展的React状态管理库,由Poimandres团队开发。它的核心理念是提供一个简单直接的API来管理应用状态,同时保持优秀的性能和开发者体验。
与Redux等传统方案相比,Zustand具有以下特点:
- 极简API,学习曲线平缓
- 不需要繁琐的Provider包裹
- 自动处理依赖跟踪和优化渲染
- 支持中间件扩展
- 体积小巧(约1kB)
基本用法
安装
npm install zustand
# 或
yarn add zustand
创建store(核心用法)
import { create } from 'zustand'
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}))
这一步是Zustand的核心用法,后文会对这里的书写进行详细说明
在组件中使用
function Counter() {
const { count, increment, decrement, reset } = useStore();
return (
<div>
<h1>{count}</h1>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}
Zustand的核心,create的书写
在上面的部分中,最重要的就是书写Zustand的create部分了,在 Zustand 中,create 函数的回调函数是定义 store 的核心部分,它决定了 store 的初始状态和状态更新方法。这个回调函数的写法非常灵活,但通常遵循一定的模式。下面我会详细解释如何编写这个回调函数,并提供不同场景的示例。
1. 回调函数的基本结构
create 的回调函数接收两个主要参数:
set: 用于更新状态(必须)。get: 用于读取当前状态(可选)。
import { create } from 'zustand';
const useStore = create((set, get) => ({
// 初始状态
count: 0,
// 更新状态的方法
increment: () => set((state) => ({ count: state.count + 1 })),
}));
2. 如何编写回调函数
(1) 定义初始状态
在返回的对象中直接声明初始值:
const useStore = create(() => ({
count: 0, // 初始状态
name: "Zustand",
}));
⚠️ 如果这样写,状态将无法更新(因为没有
set),所以通常不推荐。
(2) 使用 set 更新状态
set 有两种用法:
方式 1:直接传入新状态
const useStore = create((set) => ({
count: 0,
reset: () => set({ count: 0 }), // 直接替换为 { count: 0 }
}));
方式 2:基于当前状态计算新状态
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })), // 依赖当前 state
}));
(3) 使用 get 读取当前状态
如果需要在方法中获取最新状态(而不是依赖闭包中的 state),可以用 get:
const useStore = create((set, get) => ({
count: 0,
logCount: () => {
const currentCount = get().count; // 读取当前 count
console.log(currentCount);
},
}));
(4) 异步更新状态
Zustand 完全支持异步操作:
const useStore = create((set) => ({
data: null,
loading: false,
fetchData: async () => {
set({ loading: true });
const response = await fetch('https://api.example.com/data');
const result = await response.json();
set({ data: result, loading: false }); // 异步更新
},
}));
总结一下书写create回调函数的重要规则
重要规则
set必须声明:即使你不用它,Zustand 也要求回调函数的第一个参数是set。- 状态不可变:每次更新必须返回新对象(Zustand 内部会处理优化)。
get是可选的:只有需要读取最新状态时才用。
Zustand与Redux的比较
| 特性 | Zustand | Redux |
|---|---|---|
| 学习曲线 | 低 | 中到高 |
| 样板代码 | 极少 | 较多 |
| 性能优化 | 自动选择器优化 | 需要手动优化 |
| 中间件 | 支持 | 支持 |
| DevTools | 需要中间件 | 内置支持 |
| 包大小 | ~1kB | ~5kB + react-redux |
最佳实践
- 按功能拆分store:虽然可以在一个store中管理所有状态,但建议按功能拆分
- 合理使用选择器:只订阅组件实际需要的状态部分
- 利用中间件:根据需求添加持久化、日志等中间件
- 避免过度嵌套:保持状态结构扁平化
- 类型安全:在TypeScript项目中充分利用类型推断