React 团队一直致力于提升性能以及用户体验。在计算中,memoization 是一种常见的优化手段,主要用于通过存储昂贵的函数调用的结果并在相同的输入再次出现时返回缓存的结果来加速计算机程序。因此,React.memo 诞生了。
React 官方对 memo 的介绍是这样的:
显而易见,使用 memo 可以让我们的组件避免一些不必要的 re-render 场景:
当决定更新 DOM 时,React 首先渲染你的组件,然后将结果与之前的渲染进行比较。如果渲染结果不同,React 会更新 DOM。
当组件被包装在 React.memo()
中时,React 会渲染组件并记住这一次的结果。在下一次渲染之前,如果新的 props 相同,React 会跳过下一次渲染,直接复用当前 memo 的结果并返回。
那这是否意味着我们可以无脑使用 React.memo()
呢?答案显然是否定的,我们接着往下看。
props 对比
首先,React.memo 是如何对比前后两次更新的 props 的呢?
默认情况下,React.memo 会通过 Object.is 比较前后两次 props 中的每一个 prop。
如果要自定义 props 对比,你可以在第二个参数传入你自己的比较函数:
js
React.memo(Component, [compareFunc(prevProps, nextProps)]);
因此,默认情况下,如果你的组件本身没接收任何 props,那么永远会返回 React.memo 缓存的结果。
什么时候应该使用 React.memo?
1. 组件经常使用相同的 props 进行渲染
什么情况下组件在相同 props 时仍会重复渲染呢?最常见的情况就是父组件进行了渲染。
举个最极端的例子,你的组件并没有接收任何 props:
js
// Child
const Child = () => {
return <></>;
}
// Father
const Father = () => {
// state
const [state, setState] = useState();
// ...
return <><Child /></>;
}
很显然,这里的 Child
组件并不需要频繁更新,只需要渲染一次就足够了。但是每当 Father
重新渲染时(比如 state 发生了变化),那么 Child
组件都会被重新创建,从而触发 re-render。
这种场景下,使用 React.memo 包裹 Child 组件就是一个明智的选择:
js
// Child
const Child = React.memo(() => {
return <></>;
});
// Father
const Father = () => {
// state
const [state, setState] = useState();
// ...
return <><Child /></>;
}
所以,当你的组件 props 不会经常发生变化时,使用 React.memo 包裹进行渲染优化是个非常不错的选择。
2. 组件包含了大量的 UI 元素
当你的组件包含了大量的 UI 元素时,如果频繁的更新渲染可能会给用户带来很差的体验,比如卡顿。
因此,当你的组件包含了大量 UI 元素时,使用 React.memo 进行包裹也是一个不错的选择。
当然,不建议一个组件里包含大量的 UI 元素,更好的方式是将其拆解成多个尽可能小的 UI 组件,再对每个组件进行分析是否需要 memo。
什么时候避免使用 React.memo?
如果在错误的场景下使用 React.memo,不仅不会带来性能提升,反而会带来更多的性能损耗。
1. 类组件
当你的组件是一个 Class Component 时,请不要使用 React.memo
来做缓存优化。
如果你想要你的类组件拥有跟函数组件的 React.memo
有同样的效果,需要通过拓展 PureComponent
来实现。
js
class Comp extends React.PureComponent {
render() {...}
}
2. 组件的 props 经常发生变化
前面提到当组件的 props 不经常变化时,是可以使用 React.memo
的。反之则应该避免使用它。
这是因为当你用 React.memo
包裹你的函数组件时,React 在每次渲染时都会执行以下两个处理:
- 调用比较函数来判断前一个 props 和下一个 props 是否相等
- 因为 props 经常变化,所以第一步的判断总是返回 false,因此 React 还是会执行重新渲染
这个场景下使用 memo 没有任何性能优势,反而还多了一步 props 比较判断,会带来更多的性能损耗。
3. 轻量级组件
同理,当你的组件足够轻量时,props 比对的开销完全有可能大于你重新渲染的开销。这种情况下也不建议使用 React.memo,因为这并不会带来很大的性能提升。
最后
相信大家已经了解了 React.memo 以及其使用的最佳时机,在项目中合理使用 React.memo,一定能带来性能上体验上的正向收益。
如果你还想了解如何定位组件的重复渲染,相信 这篇文章 可以帮到您。
参考: