React 已经比较快了,但使用时仍很容易犯些小错误,导致其性能下降。组件挂载慢,组件树层级过深以及没必要的循环渲染都会让app感觉很慢。
幸亏有很多工具(有些甚至内置在 React 中)能帮助诊断性能问题。在这篇文章中,我将告诉你快速生成 React 应用程序的工具和技术。每个部分会有一个互动以及(希望是)有趣的演示!
工具1:The Performance Timeline
React 15.4.0 介绍了一种新的性能 timeline 特性可以让你看到组件安装、更新和卸载的时间,你还可以看到相关可视化组件的生命周期。
注:现在,该功能只适用于Chrome,Edge 和 IE,因为它实用的 User Timing API 尚未在所有浏览器上实现。
如何运行它:
- 打开你的 app 并附加查询参数: react_perf。例如,http://localhost:3000?react_perf
- 打开 Chrome DevTools 的 Performance,点击 Record.
- 执行要分析的操作。
- 停止记录。
- 检查 User Timing.
了解输出
每个颜色栏显示一个组件“工作”的时间。因为JavaScript是单线程的,当一个组件安装或渲染,都会占用主线程并防止其他代码运行。
括号内是 [update] 描述的是组件生命周期的哪一部分正在执行。timeline会把每个步骤分解,所以你可以区分出诸如[componentDidMount][componentWillReceiveProps][ctor](constructor) 和[render]的细微的时间差。
堆叠的条表示组件树。虽然在 React 中有相当深的组件树是典型的,但是如果您正在优化频繁安装的组件,它可以帮助减少包装器组件的数量,因为每个组件都有增加一点性能和内存的损耗。
这里需要注意的一点是,timeline中的数值是用于React开发构建的,所以相对于生产会慢许多。事实上,使用timeline也会使你的app变慢。虽然这些数值并不代表真实环境的性能,但是不同组件的相对时间是精确的。而且,组件是否更新并不取决于生产环境。
这里需要注意的一点是,timeline中的数值是用于React开发构建的,所以用于实际生产时会感觉比较慢。事实上,使用 timeline 也会使你的 app 变慢。虽然这些数值并不代表真实环境的性能,但是不同组件的相对时间是精确的。另外,组件是否更新并不取决于生产环境。
Demo #1
为了好玩,我在 todomvc APP 增加了一些严重的性能问题。你可以在这里试试。
要查看 timeline,打开 Chrome 开发工具,转到“Performance”选项,然后单击“Record”。再在App里添加一些 TODOs ,停止记录并查看timeline。你可以看看到底是哪些组件引起了性能问题 :)
工具#2: why-did-you-update
影响 React 中性能的最常见问题之一是不必要的渲染循环。默认情况下,React 组件将在父类渲染时重新渲染,即使他们的 props 没有改变。
例如,如果我有一个这样的简单组件:
class DumbComponent extends Component { render() { return <div> {this.props.value} </div>; } }
有一个这样的父类组件:
class Parent extends Component { render() { return <div> <DumbComponent value={3} /> </div>; } }
无论何时父组件被渲染时,DumbComponent将被重新渲染,尽管其props并没有改变。
通常,如果渲染执行完成,并且虚拟DOM并没有改动,那么它是一个无用的渲染循环,因为渲染方法应该是纯的,而且没有任何副作用的。在一个大规模的React应用程序中,检测发生这种情况的发生的位置可能很棘手,但幸运的是,我们有一个可以帮助检测的工具!
使用 why-did-you-update
why-did-you-update 是一个挂钩到 React 检测潜在的不必要的组件渲染的库。即使props 没有改变,当一个组件的渲染方法被调用时它也会进行检测。
安装程序:
- npm 安装:npm i –save-dev why-did-you-update
- 在应用程序的任何地方添加此代码:
import React from 'react' if (process.env.NODE_ENV !== 'production') { const {whyDidYouUpdate} = require('why-did-you-update') whyDidYouUpdate(React) }
注:该工具用于本地开发很好,但要确保生产环境下被禁用,因为它会让你的应用变慢。
理解输出结果
what-did-you-update用于监测你的应用程序,记录其运行情况和可能出现的不必要地组件变动。它可以让你在渲染循环之前和之后看到其属性以确定该过程是否是不必要的。
Demo #2
为了说明why-did-you-update的原理, 我将该库安装在Code Sandbox中的TodoMVC应用程序上,这是一个在线React游戏机。打开浏览器控制台并添加一些TODOs,查看输出。
演示地址.
请注意,应用程序中有几个组件是没有必要渲染的。尝试使用上述技术来预防不必要的渲染。如果正确地完成,那么在控制台中应该没有任何why-did-you-update的输出。
工具 3: React Developer Tools
React Developer Tools Chrome Chrome扩展有一个内置的可视化组件更新功能。这有助于检测不必要的 render 周期。要使用它,首先要在这里安装扩展。
然后,打开扩展通过点击“React”选项卡中DevTools并检查“高亮更新(Highlight Updates)”。
然后,简单地使用你的应用程序。使组件交互,看 DevTools发挥它的魔力。
了解输出
React Developer Tools 高亮显示在给定时间内重复渲染的组件。使用蓝色、绿色、黄色和红色表示更新的频率。
看到黄色或红色的不一定是坏事。当调整 slider 或 UI 元素频繁触发更新时就会出现这种情况。但是如果你点击一个简单的按钮,看到红色 —— 那可能就是什么东西出了问题。该工具的目的是发现更新不必要的组件。作为应用程序开发人员,您应该有一个大致的概念,在给定的时间内哪些组件应该更新。
demo #3
为了演示组件高亮,我在 TodoMVC 应用里更新了一些不必要的组件。
打开上面的链接,然后打开 React Developer Tools 并启用更新高亮。当您键入的文本输入头部时就会看到所有TODOs不必要的高亮。当你输入加快的时候,你会看到颜色的变化得更频繁。
修复不必要的渲染问题
一旦定位到了应用中的不必要重绘的组件,可以用上这些简单的修复方法。
使用 purecomponent
在上面的例子中, dumbcomponent 是其 props 的纯函数。也就是说,组件只需要在 props改变时重新渲染。React 有一个特殊类型的内置组件叫 PureComponent ,说的就是这种使用案例。
从React.PureComponent继承而不是从React.Component.
class DumbComponent extends PureComponent { render() { return <div> {this.props.value} </div>; } }