菜单

shallow 与 useShallow

相关源文件

此页面文档介绍了 Zustand 中的 shallow 比较实用程序和 useShallow React 钩子,它们对于优化 React 应用程序中的重新渲染至关重要。这些实用程序提供了高效的相等性检查机制,有助于在状态更改但派生数据保持不变时防止不必要的重新渲染。

有关选择器和通用重新渲染模式的信息,请参阅 选择器与重新渲染

概述

来源: src/shallow.ts1-3 src/vanilla/shallow.ts48-70

shallowuseShallow 实用程序是 Zustand 中性能优化的工具

  • shallow:一个比较函数,用于检查两个值是否是浅层相等的(具有相同的顶层属性)
  • useShallow:一个 React 钩子,使用浅层比较来记忆选择器函数,以防止不必要的重新渲染

shallow 函数

shallow 函数在两个值之间执行比较,确定它们是否在顶层相等。当您想比较对象、数组、Map 或 Set 而不检查深度嵌套结构时,它特别有用。

与深度比较(递归检查所有嵌套属性)不同,shallow 只检查提供的值的直接属性或元素。

shallow 的工作原理

来源: src/vanilla/shallow.ts1-70 tests/vanilla/shallow.test.tsx1-196

shallow 比较函数

  1. 首先使用 Object.is 检查值是否相同
  2. 如果不相同,则验证两个值都是对象(非 null)
  3. 对于对象,比较它们的顶层属性
  4. 对于 Map、Set 和 Array 等可迭代对象,具有专门的比较逻辑
  5. 如果值浅层相等,则返回 true,否则返回 false

比较不同数据类型

shallow 使用专门的比较逻辑处理各种 JavaScript 数据类型

数据类型比较行为
原始类型(字符串、数字、布尔值)直接与 Object.is 比较
对象比较顶层属性键和值
数组按顺序比较元素
Map比较键值对(不区分顺序)
集合比较元素(不区分顺序)
可迭代对象按迭代顺序比较元素

来源: tests/vanilla/shallow.test.tsx4-173 docs/apis/shallow.md53-152

局限性

需要了解的是,shallow 只检查顶层相等性。如果您的状态包含嵌套对象,即使父对象引用保持不变,shallow 也无法检测到嵌套属性的更改。

来源: docs/apis/shallow.md157-226

useShallow 钩子

useShallow 钩子旨在优化订阅 Zustand 存储(带选择器函数)的 React 组件。它会记忆化选择器,仅当选定状态根据浅层比较发生更改时才触发重新渲染。

useShallow 的工作原理

来源: tests/shallow.test.tsx36-187 docs/hooks/use-shallow.md27-35

使用 useShallow 的好处

useShallow 的主要优点是防止 React 组件不必要的重新渲染。当选择器返回计算值(如键数组或数据过滤子集)时,组件仅在该计算值实际更改时才会重新渲染,而不是在状态的不相关部分更改时。

示例用法模式

以下模式展示了 useShallow 的优势

不使用 useShallow

使用 useShallow

来源: docs/guides/prevent-rerenders-with-use-shallow.md16-63 docs/hooks/use-shallow.md39-197

实际用法示例

使用 shallow 进行直接比较

shallow 函数可以直接用作创建 Store 或比较值的自定义相等函数

来源: tests/shallow.test.tsx9-33

使用 useShallow 防止重新渲染

一种常见的模式是使用 useShallow 处理计算值,以防止不必要的重新渲染

当与返回数组、对象或其他引用类型的选择器一起使用时,useShallow 尤其有价值,因为它可以防止在这些结构的内部没有改变时发生重新渲染,即使它们是新创建的对象。

来源: docs/hooks/use-shallow.md186-262

内部实现细节

shallow 的实现比表面上看起来要复杂,因为它使用专门的比较逻辑来处理各种 JavaScript 数据结构

  1. 对于原始值,它使用 Object.is
  2. 对于对象,它会比较可枚举的属性
  3. 对于 Map 和 Set 等可迭代对象,它有自定义的比较逻辑
  4. 对于其他对象,它会回退到比较它们的条目

实际实现包括 compareEntriescompareIterables 等实用函数,以适当处理不同的数据结构。

来源: src/vanilla/shallow.ts1-70

与 Zustand 生态系统集成

来源: docs/hooks/use-shallow.md1-266 tests/vanilla/subscribe.test.tsx1-123 tests/shallow.test.tsx1-187

在 Zustand 生态系统中,shallowuseShallow 与其他功能协同工作

  1. shallow 可用作 createWithEqualityFn 中的默认相等函数
  2. useShallow 与常规的 create API 配合使用以优化重新渲染
  3. 这两个实用程序补充了 subscribeWithSelector 中间件,它也使用相等函数

性能考量

在使用 shallowuseShallow 时,请牢记这些性能注意事项

  1. shallow 比深度相等检查更快,但仍有一些开销
  2. 对于非常大的对象或数组,即使是浅层比较也可能变得昂贵
  3. useShallow 根据浅层相等性缓存结果,从而提高重复返回相似数据结构的性能
  4. 当您的选择器返回新创建的对象、数组或其他引用类型时,请使用 useShallow

来源: tests/shallow.test.tsx61-120

故障排除

尽管使用了 useShallow,组件仍会重新渲染

如果您在使用 useShallow 后,组件仍然重新渲染,请检查:

  1. 您的选择器可能返回了一个深度嵌套的结构,即使相关数据未更改,该结构也会发生变化
  2. 选择器可能捕获了频繁更改的外部值(请考虑依赖项)
  3. 您选择的状态切片可能确实频繁更改

使用 shallow 时比较结果不正确

如果 shallow 没有产生预期的比较结果

  1. 验证您没有比较深度嵌套的对象(`shallow` 只检查顶层)
  2. 检查您是否正在比较需要特殊处理的自定义对象
  3. 请记住,具有相同属性但引用不同的对象会被 `shallow` 视为相等,但无法检测到嵌套内容的更改

来源: docs/apis/shallow.md155-226

总结

shallowuseShallow 是 Zustand 中强大的工具,它们通过防止不必要的重新渲染来帮助优化 React 应用程序。它们提供高效的状态值比较和选择器记忆化,从而提高性能,尤其是在处理从状态派生的计算值时。

通过理解和正确实现这些工具,您可以显著提高 Zustand 驱动的 React 应用程序的性能。