[关闭]
@levinzhang 2023-02-24T09:11:02.000000Z 字数 2921 阅读 365

优化React前端性能的五个技巧

摘要

本文在React的虚拟DOM、不可变数据结构、生产化构建等方面给出了优化React Web应用的常见技巧。

作者|Piumi Liyana Gunawardhana
译者/策划|张卫滨


在现代Web应用开发中,性能是获得更好的用户体验的关键。使用React能够产生直观的用户界面,为众多应用提供更强大的用户体验,而且无需花费很多的精力来显式地优化性能。但是,开发人员在构建大型应用时,往往受困于性能问题,我们可以采用各种方法来进一步优化React应用的性能。

在本文中,我将讨论提升React前端性能的五个技巧。

1.使用React.PureComponent避免进行协调

React使用了虚拟DOM(VDOM)的概念,在这种概念中,像ReactDOM这样的库会在内存中维护用户界面的“虚拟”表述,并使其与“实际”的DOM保持同步。这个过程叫做协调(reconciliation)。

即便只更新已修改的DOM节点,重新渲染也会需要时间。生命周期函数shouldComponentUpdate()会在重新渲染过程开始之前被调用,这通常都不是什么问题,但是,如果延迟很明显的话,我们可以通过覆盖shouldComponentUpdate()来加速这一过程。该函数的默认实现会返回true,即让React来处理更新,如下所示:

  1. shouldComponentUpdate(nextProps, nextState) {
  2. return true;
  3. }

如果你知道自己的组件在某些情况下不需要更新的话,那么可以从shouldComponentUpdate()中返回false来完全省略渲染过程。

在React“纯”组件的帮助下,这种优化策略可以变得更加容易、更加自动化。PureComponent使用浅层(shallow)属性和状态对比来实现其shouldComponentUpdate()

这意味着它会对原始数据类型的值和对象的引用进行对比。因此,在使用React.PureComponent时,我们需要满足如下两个先决条件:

2.使用不可变的数据结构

假设我们要思考一种有效的方式来自动探测复杂属性或状态变更,这里就是不可变数据结构的用武之地了。

使用不可变数据结构背后的理念很简单:与其直接对包含复杂数据的对象进行修改,不如创建一个包含数据变更的副本。因此,识别对象变化就可以像比较两个对象的引用一样容易。

为了自动检查复杂的状态变更,可以组合使用React.PureComponent和不可变数据结构。例如,借助像Redux这样的状态管理工具,如果应用中的状态是不可变的,我们可以将所有的状态对象保存到一个单独的存储中,这样就可以很容易地实现撤销和重做功能。

如果能够使用提供不可变数据结构的库会更好。在处理高度嵌套的对象时,更新不可变的对象可能是一项挑战。如果你遇到这种问题,可以考虑使用Immerimmutability-helper。这些库能够让我们创建更加易读的代码,同时保留了不可变性的优势。

使用不可变数据结构会带来一些收益:

3.使用生产化的构建

当创建React应用时,你会看到很多有用的警告和错误信息。在开发软件的过程中,它们能够让发现缺陷和问题变得更加容易。但是,它们在性能方面是有代价的。

因此,如果你要做基准测试或者遇到性能问题,请使用最小化的生产化构建来测试你的React应用。终端用户不需要React在开发环境中运行的这些代码片段。这些不相关的代码都可以在生产环境中移除。

如果你使用create-react-app进行的项目初始化的话,那么可以使用npm run build来生成没有这些额外代码的生产化构建。如果你直接使用Webpack的话,那么可以运行webpack -p(相当于webpack — optimize-minimize — define process.env.NODE ENV=”’production’”)。

在你项目的/build子目录下,现在将会包含应用的生产化构建。请记住,这仅在生产化部署时才是必要的,在通常的开发中,依然可以使用npm start

4.多个分块文件

在项目初期,你的React应用可能只有几个组件。但是,随着不断添加新的功能和依赖,应用也会随着时间的推移而不断增长。不知不觉中,你可能就会有一个非常庞大的生产化文件。

对于单页的React应用,我们通常会将所有的前端JavaScript代码打包到一个最小化的文件中。对于中小规模的应用来说,这是合理的。但是,当应用的规模扩大时,将这些打包的JavaScript代码发送到浏览器会耗费大量的时间,从而影响应用的性能。

如果你使用Webpack来构建React项目的话,那么可以使用它的代码拆分功能,也就是将要构建的应用代码分割成多个“块(chunk)”。例如,我们可以使用CommonsChunkPlugin将应用打包成两个独立的文件,也就是将供应商或第三方库的代码与我们的应用代码区分开,并按需传递给浏览器。这样的话,我们最后会得到名为vendor.bundle.jsapp.bundle.js的两个文件。通过拆分文件,我们的浏览器能够减少缓存并且能够并行加载资源,以尽量减少加载时间的延迟。

按需拆分代码是Webpack的一个优秀特性。它可以将代码分割成较小的块,这些块可以在需要时加载。这实现了最小的初始下载量,减少了应用的加载时间。然后,浏览器可以根据应用的需要下载更多的代码块。

5.虚拟化长列表

如果你正在展示一个包含大量数据的长列表,那么在给定的时间,你应该仅在可见的视口(viewport)内渲染一部分的数据。数据仅在视口中显示,当列表向下滚动时,更多的数据会被渲染出来。这种技术被称为“窗口化(windowing)”。该技术可以大大减少重新渲染组件所消耗的时间以及所生成的DOM节点的数量,因为每次它仅渲染很小的一部分数据行。

知名的窗口化库是react-windowreact-virtualized。它们提供了几个可重用的组件来展示数据表格、列表和表格化的数据。当然,如果你需要满足应用特定的需求,那么可以像Twitter那样不断地开发自己的窗口组件。

最后的思考

React Web应用的性能是由其组件的简洁性决定的。因此,在解决性能问题之前,了解React组件的工作方式、渲染和diffing技术是至关重要的。在React生命周期方法的帮助下,我们可以避免不必要的组件渲染。如果消除了这些限制,应用能够像用户期望的那样流畅运行。所以,在增强React应用的性能时,你应该考虑所有的这些想法。

尽管还有其他各种方法来增强React应用的性能,但我希望这篇文章能帮助你获得优化React前端性能的最佳技巧。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注