Zustand 工具
一个基于 zustand 的状态管理工具,它简化了 zustand 的使用方式,并提供了更好的类型支持和性能优化。
基本用法
创建 Store
使用 createStore
函数来创建一个 store,它接收一个配置对象,包含 state
和 actions
两个字段:
import { createStore } from "@next-tools/tools/zustand";
const store = createStore({
state: {
count: 0,
user: { name: "John" },
},
actions: {
increment: (state, amount: number) => {
state.count += amount;
},
setUserName: (state, name: string) => {
state.user.name = name;
},
},
});
配置说明
state
: 定义初始状态,必须是一个对象actions
: 定义修改状态的方法,每个方法接收两个参数:state
: 当前状态,可以直接修改(基于 immer)payload
: 方法的参数
状态管理
获取状态
// 获取完整状态
const state = store.getState();
// 在 React 组件中使用
const count = store.useSnapshot((state) => state.count);
修改状态
// 使用 actions
store.actions.increment(1);
store.actions.setUserName("Jane");
React 集成
useSnapshot vs useShallowSnapshot
useSnapshot
useSnapshot
用于在组件中订阅状态变化:
function Counter() {
// 订阅完整状态
const state = store.useSnapshot();
// 使用选择器只订阅部分状态
const count = store.useSnapshot(s => s.count);
return <div>{count}</div>;
}
useShallowSnapshot
useShallowSnapshot
用于性能优化,它会对选择器返回的值进行浅层比较来减少不必要的重渲染:
function UserInfo() {
// 只有当返回的对象经过浅比较后发生变化时才会重渲染
// 例如:user.name 改变会导致返回新的对象,触发重渲染
const user = store.useShallowSnapshot(s => s.user);
return <div>{user.name}</div>;
}
最佳实践
- 使用选择器获取状态:
// ✅ 好的做法:只订阅需要的状态
const count = store.useSnapshot((s) => s.count);
// ❌ 避免订阅整个状态:可能导致不必要的重渲染
const state = store.useSnapshot();
- 合理使用 useShallowSnapshot:
// ✅ 返回对象时使用 useShallowSnapshot
const userInfo = store.useShallowSnapshot((s) => ({
name: s.user.name,
age: s.user.age,
}));
// ❌ 返回原始类型时不要使用 useShallowSnapshot
const count = store.useShallowSnapshot((s) => s.count); // 没有优化效果
性能优化
手动优化
- 使用选择器减少重渲染:
// 只有 count 变化时重渲染
const count = store.useSnapshot((s) => s.count);
- 对象类型使用 useShallowSnapshot:
// 只有 user 对象引用变化时重渲染
const user = store.useShallowSnapshot((s) => s.user);
- 避免频繁的状态更新:
// ✅ 批量更新
store.actions.updateUser({
name: "Jane",
age: 25,
});
// ❌ 避免多次更新
store.actions.setName("Jane");
store.actions.setAge(25);
自动优化示例
通过 Babel 插件,我们提供了自动优化功能,可以在编译时自动优化状态访问模式。以下是两个主要的优化场景:
1. 解构语法优化
编译前的代码:
function UserProfile() {
// 直接解构会订阅整个状态
const { user, settings } = store.useSnapshot();
return (
<div>
<h1>{user.name}</h1>
<p>{settings.theme}</p>
</div>
);
}
编译后的代码:
function UserProfile() {
// 自动生成选择器函数,只订阅需要的字段
const selector = (state) => ({
user: state.user,
settings: state.settings
});
// 使用 useShallowSnapshot 优化性能
const { user, settings } = store.useShallowSnapshot(selector);
return (
<div>
<h1>{user.name}</h1>
<p>{settings.theme}</p>
</div>
);
}
2. 属性访问优化
编译前的代码:
function Counter() {
// 订阅了整个状态
const state = store.useSnapshot();
return (
<div>
<p>Count: {state.count}</p>
<p>Total: {state.total}</p>
</div>
);
}
编译后的代码:
function Counter() {
// 自动生成选择器函数,只订阅使用到的字段
const selector = (state) => ({
count: state.count,
total: state.total
});
// 转换为使用选择器的形式
const state = store.useSnapshot(selector);
return (
<div>
<p>Count: {state.count}</p>
<p>Total: {state.total}</p>
</div>
);
}
这些优化会在编译时自动应用,无需手动编写选择器函数。通过自动生成选择器和使用 useShallowSnapshot
,可以有效减少不必要的重渲染,提高应用性能。
类型支持
store 的类型会自动推导:
const store = createStore({
state: { count: 0 },
actions: {
increment: (state, amount: number) => {
state.count += amount;
},
},
});
// ✅ 类型安全
store.actions.increment(1);
// ❌ 类型错误
store.actions.increment("1"); // Type 'string' is not assignable to type 'number'