useShallow react
useShallow 是一个 React Hook,可用于优化重新渲染。
类型
签名
参考
useShallow(selectorFn)
参数
selectorFn:一个函数,用于返回基于当前状态的数据。
返回值
useShallow 返回一个选择器函数的记忆化版本,它使用浅比较来实现记忆化。
用法
编写记忆化的选择器
首先,我们需要创建一个 store 来保存小熊一家的状态。在这个 store 中,我们定义了三个属性:papaBear、mamaBear 和 babyBear,它们分别代表小熊一家的不同成员,以及各自那份燕麦粥锅的大小。
接下来,我们会创建一个 BearNames 组件,它获取状态中的键(也就是小熊一家的成员),并把它们显示出来。
然后,我们会创建一个 UpdateBabyBearMeal 组件,它会定期更新小熊宝宝的餐食选择。
最后,我们把这两个组件组合到 App 组件中,看看它们如何运作。
代码应该像这样:
一切看起来可能都没问题,但有个小问题:即使名字没有变化,BearNames 组件也会不断重新渲染。这是因为只要状态的任何部分发生变化,组件就会重新渲染,即使我们关心的那部分(名字列表)并没有变化。
为了解决这个问题,我们用 useShallow 来确保只有当状态中实际的键发生变化时,组件才会重新渲染:
代码应该像这样:
通过使用 useShallow,我们优化了渲染过程,确保组件只在必要时重新渲染,从而提升了整体性能。
疑难解答
从 store 中读取多个值时出现 “Maximum update depth exceeded”
从 v5 开始,每次渲染都返回新引用的选择器可能触发无限更新循环,因为默认的相等性检查是 Object.is。最常见的情况是在选择器内部把多个值打包成一个对象。下面的写法会触发该错误:
这个包装对象在每次渲染时都会被重新创建,因此每次比较都会失败,组件便会陷入循环重新订阅。
用 useShallow 包裹选择器,这样就会按引用比较包装对象的各个属性,而不是比较包装对象本身:
另一种做法是为每个值分别使用自己的选择器来订阅 —— 这样就不存在需要重新创建的包装对象:
关于底层的这一行为变更,请参阅 v5 迁移指南中的 要求稳定的选择器输出。