Zustand
https://docs.pmnd.rs/zustand/getting-started/introduction
v5 一个小,快,可扩展的状态管理解决方案
它基于 hooks 的舒适 API,而不是样板代码和选项式
通过约定式来保证 精简,灵活
zustand 不关心你的 action 函数是否异步,只用在合适的时候调用 set。
(虽然 setState 和 getState 两个 API 也可以达到相同效果,但是回调函数更符合单一责任原则
useCountStore.getState().count;
创建 store
import { create } from "zustand";
// set
const useStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
updateBears: (newBears) => set({ bears: newBears }),
}));
与组件绑定
调用 hooks 可以拿到在 state 上拿到 get 和 set
function BearCounter() {
const bears = useStore((state) => state.bears);
return <h1>{bears} around here...</h1>;
}
function Controls() {
const increasePopulation = useStore((state) => state.increasePopulation);
return <button onClick={increasePopulation}>one up</button>;
}
与 redux 对比
zustand 和 redux 都基于不可变的状态模型
但是 redux 需要把 app 包在 context provider 中
zustand 不需要
redux tookit 使用 immerjs 控制 draft state,
渲染优化
都推荐使用 selectors 进行渲染优化
// zustand 的 selector
const count = useCountStore((state) => state.count);
const increment = useCountStore((state) => state.increment);
const decrement = useCountStore((state) => state.decrement);
// redux 的 selector
const count = useSelector((state) => state.count);
更新 state
(新值)=》set(()=>({原 key: 新对象}))
const usePersonStore = create<State & Action>((set) => ({
firstName: "",
lastName: "",
updateFirstName: (firstName) => set(() => ({ firstName: firstName })),
updateLastName: (lastName) => set(() => ({ lastName: lastName })),
}));
深层对象修改
type State = {
deep: {
nested: {
obj: { count: number },
},
},
};
// 一般做法
//不可变数据!!
normalInc: () =>
set((state) => ({
deep: {
...state.deep,
nested: {
...state.deep.nested,
obj: {
...state.deep.nested.obj,
count: state.deep.nested.obj.count + 1
}
}
}
})),
// 使用immer
immerInc: () =>
set(produce((state: State) => { ++state.deep.nested.obj.count })),
// 还有使用optics-ts和ramda的方案
不可变 state 和 merging
set 能自动进行单层的合并
所以不需要...state
set((state) => ({ count: state.count + 1 }));
但是多层(除了第一层)都需要
import { create } from "zustand";
const useCountStore = create((set) => ({
nested: { count: 0 },
inc: () =>
set((state) => ({
nested: { ...state.nested, count: state.nested.count + 1 },
})),
}));
为了禁止首层自动合并 可以把 set 的第二个参数改为 true
set((state) => newState, true);