使用 Zustand/React 获取多个状态(简写语法)

wen*_*nzf 7 reactjs zustand

在状态更改时重新渲染方面,从Zustand存储获取状态的两种方式是否相同?

文档中描述的方法:

const nuts = useStore(state => state.nuts)
const honey = useStore(state => state.honey)
Run Code Online (Sandbox Code Playgroud)

速记:

const { nuts, honey } = useStore()
Run Code Online (Sandbox Code Playgroud)

YSK*_*YSK 17

简答

不,这些方法并不相同。

长答案

正如zustand 自述文件中提到的:

获取所有内容

您可以,但请记住,这将导致组件在每次状态更改时更新!

常量状态 = useStore()

因此,当您使用选择器选择某些状态切片时,组件只会在所选值发生变化时更新/重新渲染。

当您调用useStore()而不向其传递任何参数时,您实际上是在为组件订阅整个状态。作为一个比喻,您可以说“zustand 将要求组件在状态树中任何位置的任何状态更改时更新/重新渲染”。简写语法中的对象解构只是以更快的方式将变量分配给对象属性的语法糖。useStore()返回(并订阅组件)的值仍然是整个状态。

因此,如果您使用const { nuts, honey } = useStore(),您可能会遇到性能问题。这些问题是否会引人注目取决于应用程序,但我想说,只需使用选择器就足够简单,而不必担心它。

进一步建议

如果您需要在一次调用中选择所有状态切片useStore(...),建议的方法是使用合适的选择器。引用选择多个状态切片

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)
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢 zustand,但是这个语法使用起来非常粗糙,特别是因为“shallow”不喜欢在 VSCode 中自动导入 (2认同)

Ben*_*XVI 7

不,它们并不相同:第一个仅当所选属性更改时才会重新渲染;每当商店的任何属性发生变化时,第二个都会重新渲染。

这个问题的动机似乎是为了避免使用 Zustand 获取多个状态的冗长(正如ICW 也评论的那样,这可能会很痛苦。)

您可以通过几种不同的方式为多个 zustand 导入实现更简洁的语法。

选项1

让我们定义这个辅助函数:

function useMulti(useFunc, ...items) {
  return items.reduce((carry, item) => ({
    ...carry,
    [item]: useFunc(state => state[item]),
  }), {})
}
Run Code Online (Sandbox Code Playgroud)

定义此包装函数后,不要编写以下内容:

const {nuts, honey} = useStore(state => ({
  nuts: state.nuts,
  honey: state.honey,
}), shallow)
Run Code Online (Sandbox Code Playgroud)

你可以这样写:

const {nuts, honey} = useMulti(useStore, 'nuts', 'honey')
Run Code Online (Sandbox Code Playgroud)

包装函数只是提供一些用于选择多个状态的语法糖。

  • 请注意,在内部,对每个请求的 propuseMulti使用单独的调用。useStore因此,状态失效相当于使用zustand/shallowwithout useMulti
  • 另请注意,它useMulti仅适用于商店的顶级属性:例如,useMulti如果您想要 fetch ,则需要更复杂的实现。state.x.y.z

如果您不喜欢 的函数调用风格useMulti(useStore(...)),您可以利用专门useMulti()为以下内容创建一个包装函数useStore()

export const useStoreMulti = (...items) => useMulti(useStore, ...items)
Run Code Online (Sandbox Code Playgroud)

这允许你写

const {nuts, honey} = useStoreMulti('nuts', 'honey')
Run Code Online (Sandbox Code Playgroud)

选项2

单独导入它们会更干净。如果您选择许多不同的商店道具,则尤其如此:请考虑以下内容,其中 zustand 非常冗长:

const {
  nuts,
  honey,
  salmon,
  berries,
  fruit,
  insects,
  carrion,
  newbornElk,
  roots,
  garbage,
} = useStore(state => ({
  nuts: state.nuts,
  honey: state.honey,
  salmon: state.salmon,
  berries: state.berries,
  fruit: state.fruit,
  insects: state.insects,
  carrion: state.carrion,
  newbornElk: state.newbornElk,
  roots: state.roots,
  garbage: state.garbage,
}), shallow)
Run Code Online (Sandbox Code Playgroud)

与此相比,大致等效:

const nuts = useStore(state => state.nuts)
const honey = useStore(state => state.honey)
const salmon = useStore(state => state.salmon)
const berries = useStore(state => state.berries)
const fruit = useStore(state => state.fruit)
const insects = useStore(state => state.insects)
const carrion = useStore(state => state.carrion)
const newbornElk = useStore(state => state.newbornElk)
const roots = useStore(state => state.roots)
const garbage = useStore(state => state.garbage)
Run Code Online (Sandbox Code Playgroud)

减少每次调用字符数的一种方法是定义本地助手:

const localUse = (prop) => useStore(state => state[prop])

const nuts = localUse('nuts')
const honey = localUse('honey')
const salmon = localUse('salmon')
const berries = localUse('berries')
const fruit = localUse('fruit')
const insects = localUse('insects')
const carrion = localUse('carrion')
const newbornElk = localUse('newbornElk')
const roots = localUse('roots')
const garbage = localUse('garbage)
Run Code Online (Sandbox Code Playgroud)