- tags:: Zustand
- source:: Zustand-入门, Working with Zustand | TkDodo’s blog
内容
仅导出自定义的子 hooks,不暴露原始 store hook
// ⬇️ not exported, so that no one can subscribe to the entire store
const useBearStore = create((set) => ({
bears: 0,
fish: 0,
increasePopulation: (by) =>
set((state) => ({ bears: state.bears + by })),
eatFish: () => set((state) => ({ fish: state.fish - 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
// 💡 exported - consumers don't need to write selectors
export const useBears = () => useBearStore((state) => state.bears)
不建议导出 useBearStore
使用原子选择器
import shallow from 'zustand/shallow'
// ⬇️ much better, because optimized
const {bears, fish} = useBearStore(
(state) => ({bears: state.bears, fish: state.fish}),
shallow
)
选择器判断更新的条件是严格相等,所以对象或数组每次渲染都会变化,导致组件更新。
解决方案是使用浅比较 shallow
或者使用多个独立的自定义 hooks 分别导出各个属性
actions 和 state 分离
状态更新函数是静态函数,本质上不属于状态,所以将它们合并在 actions 对象下,使用的时候只需要一个选择器就可以获得所有的 actions
const useBearStore = create((set) => ({
bears: 0,
fish: 0,
// ⬇️ separate "namespace" for actions
actions: {
increasePopulation: (by) => set((state) => ({bears: state.bears + by})),
eatFish: () => set((state) => ({fish: state.fish - 1})),
removeAllBears: () => set({bears: 0})
}
}))
export const useBears = () => useBearStore((state) => state.bears)
export const useFish = () => useBearStore((state) => state.fish)
// 🎉 one selector for all our actions
export const useBearActions = () => useBearStore((state) => state.actions)
保持状态原子化、小型化,复杂逻辑使用状态组合
组合状态的自定义 hook:
const currentUser = useCredentialsStore((state) => state.currentUser)
const user = useUsersStore((state) => state.users[currentUser])
结合其他库
在自定义 hooks 可以结合使用 reac query 和 zustand。
其他库同理类推
Model Actions as Events, not Setters
编码规则:将业务逻辑保留在状态 store 中,而不是在组件中。
我不是很认可这个编码规则,比如在结合 react query 使用时,通常需要在 react 组件中使用,在 store 中是无法直接地拿到一些 react query 状态的。
且将业务逻辑全部保留在 store 中会让 store 逻辑变得越来越臃肿,后期维护时难以分辨哪些逻辑之间是相互关联的,哪些逻辑之间是无关的。 所以我倾向于简化 actions 逻辑,除了一些统一的数据处理逻辑实现在 actions 中,其他业务逻辑放到逻辑关联的合适的 react 组件中。