React的速度快如闪电。通常情况下,它的速度快到让我们很难在机器上的沙盒中重新创造出性能问题。因此,我们可能会认为,无论我们做什么,我们的网络应用都会顺利地运行。
但这是一个陷阱。开发人员通常使用强大的机器和互联网连接来构建Web应用。然而,我们的高性能环境可能会对我们隐藏性能问题,而这些问题会伤害我们的用户。与开发者不同,我们的许多用户在网络连接不好的地方使用中层移动智能手机访问我们的网络应用。
但你的应用程序的速度和性能很重要,对转换率有重大影响。
如果我们不分析性能,因为我们的机器和互联网连接相对强大,我们将不知道伤害我们用户的性能问题,并随后伤害我们的转换率。
本文将介绍一个沙盒,其中有一个由小的React反模式引起的性能问题。然后,我将告诉你如何使用库Why Did You Render来检测它,以及如何解决这个问题。
重现性能问题
下面的应用程序模拟了一个标题,随着用户的滚动而改变其大小。一个有很多行的列表被用来代表一个中到大型的应用程序。
注意:在实践中,我们希望把这么长的列表变成虚拟列表,但在我们的案例中,我们只用它来模拟一个应用程序。
我们的应用程序在滚动时,标题高度变化的动画有性能问题。
这里是沙盒。
<iframe src="https://codesandbox.io/embed/performance-issue-in-react-bjp5o?fontsize=14&hidenavigation=1&theme=dark"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="Performance Issue in React"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
为了在强大的机器上重现性能问题,我建议通过节制CPU来人为地降低浏览器的速度。你可以在Chrome浏览器中使用性能选项卡来做到这一点。
在研究性能问题时,使用这个重要的工具来运行你的应用程序,看看事情在较慢的设备上是如何运作的,这是非常好的做法。
你能检测出代码中导致性能问题的原因吗?
用Why Did You Render检测错误
发现问题的通常方法是使用React或Browser dev-tools。许多优秀的文章演示了如何深入调试。
简而言之,我们打开浏览器的dev-tools(本例中是Chrome的dev-tools,但其他现代浏览器也有类似的功能),在重现该问题时记录几秒钟。
然后我们停止分析器。我们可以立即看到,Main 组件和它的许多孩子,在每一个滚动事件中都会重新显示,导致应用程序的停顿。
但是,在我们跳到代码并试图理解Main 的问题之前,让我们试试Why Did You Render。
什么是Why Did You Render?
Why Did You Render是由Welldone Software创建的一个库,它可以检测你的应用程序中的组件为什么会通过React中的猴子补丁进行重新渲染,并将通知你有可能避免的重新渲染。
注意:请确保不要在生产中添加该库,因为它降低了React的速度,甚至可能导致它在某些边缘情况下崩溃。只有在你调试性能问题时才打开它。
首先,我们从npm 添加库。
npm install @welldone-software/why-did-you-render --save
接下来,我们在项目的根目录下添加一个wdyr.js 文件。
import React from "react";
// Make sure to only include the library in development
if (process.env.NODE_ENV === "development") {
const whyDidYouRender = require("@welldone-software/why-did-you-render");
whyDidYouRender(React, {
trackAllPureComponents: true
});
}
第三,我们在index.js 中导入wdyr.js 作为我们应用程序的第一个导入。
import "./wdyr"; // <-- first import
import React from "react";
import ReactDOM from "react-dom";
...
关于详细的安装指南,请看readme。
这里是一个安装了库的沙盒。现在,如果你滚动浏览,你将在控制台得到以下信息。
Main是*"由于道具变化而重新渲染的"*- 有问题的道具是
style style已经收到不同的对象,这些对象的值是相等的:
{paddingTop: 350} !== {paddingTop: 350}Main被App重新渲染,而App则因为useState钩子的触发而被重新渲染。
正如你所看到的,我们可以很清楚地了解到为什么Main 会被重新渲染。基于这些信息,我们可以推断出这个问题是由处理纯组件时普遍存在的React反模式引起的。
让我们看一下App.js 。
export default function App() {
const headerHeight = useHeaderScroll({
min: 50,
max: maxHeaderHeight,
maxOffset: 3000
});
return (
<div className="App">
<Header style={{ height: headerHeight }} />
<Main style={{ paddingTop: maxHeaderHeight }} />
</div>
);
}
当滚动发生时,钩子useHeaderScroll 导致App 重新渲染。这个重新渲染导致Main 元素被重新创建。
<Main style={{ paddingTop: maxHeaderHeight }} />
现在,因为Main 是一个纯组件,当App 重新渲染时,它不应该被重新渲染,因为看起来,它的道具和之前的App 的渲染是一样的。然而,在现实中,style 道具在每次渲染时都是一个新对象。
{ paddingTop: maxHeaderHeight } !== { paddingTop: maxHeaderHeight }
调试React应用程序
解决性能问题的一个简单方法是,只把相关的值传给Main ,而不是style 对象。
让我们改变一下。
<Main style={{ paddingTop: maxHeaderHeight }} />
改成这样。
<Main paddingTop={paddingTop} />
Main 将不再重新渲染,因为它唯一的道具始终是paddingTop={350} 。
现在我们只需要确保Main 被相应地调整为期望paddingTop 作为道具,而不是style 。
const Main = ({ paddingTop } /* instead of {style} */) => {
你可以在下面的沙盒中找到没有性能问题的修正后的应用程序。
总结
使用Why Did You Render可以非常有效地帮助识别React应用中的bug,即使是在通常不会寻找的地方。它的报告也非常详细,所以你可以知道到底是哪里出了问题。我的建议是,至少用它来运行你的初始页面加载,看看你如何能在几分钟内加快它。谢谢你的阅读。
The post DebuggingReact performance issues with Why Did You Renderappeared first onLogRocket Blog.