Zustand是一个使用简化的flux原理的小型、快速且可扩展的状态管理解决方案。有一个基于hooks的舒适 api,无需样板代码或自以为是的繁琐操作。
不要因为它简单就无视它。它有相当多的利器,花费了大量的时间来处理常见的陷阱,比如可怕的僵尸子问题,react并发性,以及混合渲染时的context丢失。它可能是 React 生态中可以正确地处理所有这些问题的一个状态管理库。
你可以在此处尝试现场演示。
npm install zustand # or yarn add zustand
首先创建一个store
你的store是一个hook!你可以在里面放任何东西:数据、对象、函数。 set
函数用于合并状态。
import create from 'zustand'
const useStore = create(set => ({
bears: 0,
increasePopulation: () => set(state => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 })
}))
然后绑定你的组件,这就是所有一切了!
在任何地方使用hook,不需要Provider。选择你的状态,组件将在更改时重新渲染。
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>
}
为什么zustand比redux好?
- 简单而不需要太多样板代码
- 使hook成为消费状态的主要手段
- 不将你的应用包装在context.Provider中
- [可以瞬时通知组件(不引起渲染)](#瞬态更新(对于经常发生的状态 - 变化))
为什么zustand比context好?
- 更少的样板文件
- 只在更改时渲染组件
- 集中的,基于actions的状态管理
技术
获取所有
你可以,但请记住,它会导致在每次状态更改时更新组件!
const state = useStore()
选择多个状态切片
默认情况下,它使用严格相等(old === new)
检测更改,这对于原子state picks(状态选择)很有效。
const nuts = useStore(state => state.nuts)
const honey = useStore(state => state.honey)
如果你想构造一个内部具有多个 state-picks 的单个对象,类似于 redux 的 mapStateToProps,,你可以告诉 zustand 你希望通过传递 shallow
相等函数来对对象进行浅比较。
import shallow from 'zustand/shallow'
// Object pick, re-renders the component when either state.nuts or state.honey change
const { nuts, honey } = useStore(state => ({ nuts: state.nuts, honey: state.honey }), shallow)
// Array pick, re-renders the component when either state.nuts or state.honey change
const [nuts, honey] = useStore(state => [state.nuts, state.honey], shallow)
// Mapped picks, re-renders the component when state.treats changes in order, count or keys
const treats = useStore(state => Object.keys(state.treats), shallow)
为了更好地控制重新渲染,你可以提供任何自定义的相等比较函数。
const treats = useStore(
state => state.treats,
(oldTreats, newTreats) => compare(oldTreats, newTreats)
)
缓存选择器
通常建议使用useCallback来缓存选择器。这将防止每次渲染时进行不必要的计算。它还允许 React 在并发模式下优化性能。
const fruit = useStore(useCallback(state => state.fruits[id], [id]))
如果一个选择器不依赖于作用域,你可以在渲染函数之外定义它来获得一个固定的引用而不要使用useCallback。
const selector = state => state.berries
function Component() {
const berries = useStore(selector)
状态覆盖
set 函数有第二个参数,默认为 false。它将替换状态模型,而不是去合并它。注意如无必要请不要去除你需要的部分,比如actions。
import { omit } from "lodash-es/omit"
const useStore = create(set => ({
salmon: 1,
tuna: 2,
deleteEverything: () => set({ }, true), // clears the entire store, actions included
deleteTuna: () => set(state => omit(state, ['tuna']), true)
}))
异步操作
只需在你准备好时调用set
,zustand并不关心你的操作是否是异步的。
const useStore = create(set => ({
fishies: {},
fetch: async pond => {
const response = await fetch(pond)
set({ fishies: await response.json() })
}
}))
在操作中读取状态
set
允许使用函数set(state => result)
更新状态,但你仍然可以通过 get
访问它之外的状态。
const useStore = create((set, get) => ({
sound: "grunt",
action: () => {
const sound = get().sound
// ...
}
})