原文地址:Zustand and React Context | TkDodo’s blog

使用Zustand的更多情况下,是在全局范围内将某些状态提供给一个组件子树,而不是整个应用程序。但是全局存储状态会有一些缺点:

  1. 全局 Store 是在 React 组件生命周期之外创建的,因此无法使用 Props 来初始化 Store, 对于全局 Store ,则需要先创建一个一只的默认状态,然后通过 useEffect 初始化。
	const useBearStore = create((set) => ({
  // ⬇️ initialize with default value
  bears: 0,
  actions: {
    increasePopulation: (by) =>
      set((state) => ({ bears: state.bears + by })),
    removeAllBears: () => set({ bears: 0 }),
  },
}))
 
const App = ({ initialBears }) => {
  //😕 write initialBears to our store
  React.useEffect(() => {
    useBearStore.set((prev) => ({ ...prev, bears: initialBears }))
  }, [initialBears])
 
  return (
    <main>
      <RestOfTheApp />
    </main>
  )
}
  • useEffect 初始化会导致 RestOfTheApp 渲染两次
  • 并非使用 initialBears 初始化,而是同步 Store
  1. 测试:全局 Store 会导致测试混乱和复杂,如果 Store的作用域是组件子树,那么测试会简单很多
  2. 可重用性:全局 Store 无法为可重复使用的组件建立单独的 Store,如果使用 React Context 来管理复杂的组件状态,可能会导致组件变得缓慢,并且全局 Sttore 无法多次实例化组件而不共享和覆盖彼此的状态。

使用 Context

使用 React Context 共享 Store 实例,而不是 Store 本身。因为 Store 是静态数据,不会经常变化,所有可以轻松的将其放入 React Context 中而无需担心 rerender的问题。

import { createStore, useStore } from 'zustand'
 
const BearStoreContext = React.createContext(null)
 
const BearStoreProvider = ({ children, initialBears }) => {
  const [store] = React.useState(() =>
    createStore((set) => ({
      bears: initialBears,
      actions: {
        increasePopulation: (by) =>
          set((state) => ({ bears: state.bears + by })),
        removeAllBears: () => set({ bears: 0 }),
      },
    }))
  )
 
  return (
    <BearStoreContext.Provider value={store}>
      {children}
    </BearStoreContext.Provider>
  )
}

使用 useState 初始化函数来确保 Store 只会被创建一次,也可以使用 ref 来存储 Store的引用。

使用

// useBearStore
const useBearStore = (selector) => {
  const store = React.useContext(BearStoreContext)
  if (!store) {
    throw new Error('Missing BearStoreProvider')
  }
  return useStore(store, selector)
}
 
// useBears
export const useBears = () => useBearStore(state => state.bears);

解决的问题

  1. 可以使用 Props 来初始化 Store
  2. 便于测试
  3. 重复使用组件时,每个组件都有自己的独立 Store