zustand 是一个非常时髦的状态管理库,也是 2021 年 Star 增长最快的 React 状态管理库。它的理念非常函数式,API 设计的很优雅,值得学习。
概述
首先介绍 zustand 的使用方法。
创建 store
通过 create
函数创建 store,回调可拿到 get
set
就类似 Redux 的 getState
与 setState
,可以获取 store 瞬时值与修改 store。返回一个 hook 可以在 React 组件中访问 store。
import create from 'zustand'
const useStore = create((set, get) => ({
bears: 0,
increasePopulation: () => set(state => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 })
}))
上面例子是全局唯一的 store,也可以通过 createContext
方式创建多实例 store,结合 Provider 使用:
import create from 'zustand'
import createContext from 'zustand/context'
const { Provider, useStore } = createContext()
const createStore = () => create(...)
const App = () => (
<Provider createStore={createStore}>
...
</Provider>
)
访问 store
通过 useStore
在组件中访问 store。与 redux 不同的是,无论普通数据还是函数都可以存在 store 里,且函数也通过 selector 语法获取。因为函数引用不可变,所以实际上下面第二个例子不会引发重渲染:
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>
}
如果嫌访问变量需要调用多次 useStore
麻烦,可以自定义 compare 函数返回一个对象:
const { nuts, honey } = useStore(state => ({ nuts: state.nuts, honey: state.honey }), shallow)
细粒度 memo
利用 useCallback
甚至可以跳过普通 compare,而仅关心外部 id 值的变化,如:
const fruit = useStore(useCallback(state => state.fruits[id], [id]))
原理是 id 变化时,useCallback
返回值才会变化,而 useCallback
返回值如果不变,useStore
的 compare 函数引用对比就会为 true
,非常巧妙。
set 合并与覆盖
set
函数第二个参数默认为 false
,即合并值而非覆盖整个 store,所以可以利用这个特性清空 store:
const useStore = create(set => ({
salmon: 1,
tuna: 2,
deleteEverything: () => set({ }, true), // clears the entire store, actions included
}))
异步
所有函数都支持异步,因为修改 store 并不依赖返回值,而是调