内容

仅导出自定义的子 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 组件中。