你真的会用 React.memo 吗?

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 在每次渲染时都会执行以下两个处理:

  1. 调用比较函数来判断前一个 props 和下一个 props 是否相等
  2. 因为 props 经常变化,所以第一步的判断总是返回 false,因此 React 还是会执行重新渲染

这个场景下使用 memo 没有任何性能优势,反而还多了一步 props 比较判断,会带来更多的性能损耗。

3. 轻量级组件

同理,当你的组件足够轻量时,props 比对的开销完全有可能大于你重新渲染的开销。这种情况下也不建议使用 React.memo,因为这并不会带来很大的性能提升。

最后

相信大家已经了解了 React.memo 以及其使用的最佳时机,在项目中合理使用 React.memo,一定能带来性能上体验上的正向收益。

如果你还想了解如何定位组件的重复渲染,相信 这篇文章 可以帮到您。

参考:

相关推荐
泰山小张只吃荷园6 分钟前
期末Python复习-输入输出
java·前端·spring boot·python·spring cloud·docker·容器
悦涵仙子41 分钟前
vueuse中的useTemplateRefsList
前端·javascript·vue.js
萧萧玉树41 分钟前
分布式在线评测系统
前端·c++·后端·负载均衡
haima951 小时前
ubuntu安装chrome无法打开问题
前端·chrome
放逐者-保持本心,方可放逐1 小时前
XSS 与 CSRF 记录
前端·xss·csrf·浏览器安全
徊忆羽菲1 小时前
利用HTML5和CSS来实现一个漂亮的表格样式
前端·css·html5
不爱说话郭德纲1 小时前
Stylus、Less 和 Sass 的使用与区别
前端·css·面试·less·sass·stylus
凄凄迷人2 小时前
如何调试 chrome 崩溃日志(MAC)
前端·chrome·macos·crash
蒙特网站2 小时前
网站布局编辑器前端开发:设计要点与关键考量
前端·javascript·学习·html
理想不理想v2 小时前
前端开发工程师需要学什么?
java·前端·vue.js·webpack·node.js