react 中渲染html_如何在React中识别和解决浪费的渲染

react 中渲染html

by Nayeem Reza

通过Nayeem Reza

如何在React中识别和解决浪费的渲染 (How to identify and resolve wasted renders in React)

So, recently I was thinking about performance profiling of a react app that I was working on, and suddenly thought to set a few performance metrics. And I did come across that the first thing I need to tackle is wasted renders I’m doing in each of the webpages. You might be thinking about what are wasted renders by the way? Let’s dive down in.

因此,最近,我正在考虑对正在使用的React应用进行性能分析,并突然想到设置一些性能指标。 我确实发现,我需要解决的第一件事是在每个网页中执行的渲染浪费 。 您可能正在考虑哪些浪费的渲染? 让我们深入。

From the beginning, React has changed the whole philosophy of building web apps and subsequently the way front-end developers think. With its introduction of Virtual DOM, React makes UI updates as efficient as they can ever be. This makes the web app experience neat. Have you ever wondered how to make your React applications faster? Why do moderately sized React web apps still tend to perform poorly? The problems lie in how we are actually using React!

从一开始,React就改变了构建Web应用程序的整个哲学,并随后改变了前端开发人员的思维方式。 通过引入Virtual DOM ,React使UI更新尽可能高效。 这使Web应用程序体验更简洁。 您是否曾经想过如何使您的React应用程序更快? 为什么中等大小的React Web应用仍然表现不佳? 问题在于我们如何实际使用React!

React如何工作 (How React works)

A modern front-end library like React doesn’t make our app faster wondrously. First, we developers should understand how React works. How do the components live through the component lifecycles in the applications lifetime? So, before we dive into any optimization technique, we need to have a better understanding of how React actually works under the hood.

React这样的现代前端库并不能使我们的应用程序更快地运转。 首先,我们的开发人员应该了解React的工作方式。 组件在应用程序生命周期中如何在组件生命周期中生存? 因此,在我们深入研究任何优化技术之前,我们需要更好地了解React在幕后的实际工作方式。

At the core of React, we have the JSX syntax and React’s powerful ability to build and compare virtual DOMs. Since its release, React has influenced many other front-end libraries. For example, Vue.js also relies on the idea of virtual DOMs.

作为React的核心,我们拥有JSX语法和React强大的能力来构建和比较虚拟DOM 。 自发布以来,React已经影响了许多其他前端库。 例如,Vue.js也依赖于虚拟DOM的想法。

Each React application begins with a root component. We can think of the whole application as a tree formation where every node is a component. Components in React are ‘functions’ that render the UI based on the data. That means props and state it receives; say that is CF

每个React应用程序都以一个根组件开始。 我们可以将整个应用程序视为树状结构,其中每个节点都是一个组件。 React中的组件是“功能”,它们基于数据呈现UI。 这意味着道具和它收到的状态 。 说那是CF

UI = CF(data)

Users interact with the UI and cause the change in data. The interactions are anything a user can do in our application. For example, clicking a button, sliding images, dragging list items around, and AJAX requests invoking APIs. All those interactions only change the data. They never cause any change in the UI.

用户与UI交互并导致数据更改。 用户可以在我们的应用程序中进行任何交互。 例如,单击按钮,滑动图像,拖动列表项,以及AJAX请求调用API。 所有这些交互只会更改数据。 它们永远不会导致UI发生任何变化。

Here, data is everything that defines the state of an application. Not just what we have stored in our database. Even different front-end states like which tab is currently selected or whether a checkbox is currently checked or not are part of this data. Whenever there is a change in data, React uses the component functions to re-render the UI, but only virtually:

在这里,数据就是定义应用程序状态的所有内容。 不只是我们存储在数据库中的内容。 甚至不同的前端状态(例如当前选中哪个选项卡或当前是否选中复选框)也属于此数据。 每当数据发生变化时,React都会使用组件函数来重新渲染UI,但实际上只是:

UI1 = CF(data1)UI2 = CF(data2)

React computes the differences between the current UI and the new UI by applying a comparison algorithm on the two versions of its virtual DOM.

React通过在其虚拟DOM的两个版本上应用比较算法来计算当前UI和新UI之间的差异。

Changes = Difference(UI1, UI2)

React then proceeds to apply only the UI changes to the real UI on the browser. When the data associated with a component changes, React determines if an actual DOM update is required. This allows React to avoid potentially expensive DOM manipulation operations in the browser. Examples such as creating DOM nodes and accessing existing ones beyond necessity.

然后,React继续将仅UI更改应用于浏览器上的实际UI。 当与组件关联的数据更改时,React会确定是否需要实际的DOM更新。 这使得React可以避免浏览器中潜在的昂贵DOM操作操作。 诸如创建DOM节点和访问现有节点等不必要的示例。

This repeated differentiating and rendering of components can be one of the primary sources of React performance issues in any React app. Building a React app where the differentiating algorithm fails to reconcile effectively, causing the entire app to be rendered repeatedly which is actually causing wasted renders and that can result in a frustratingly slow experience.

组件的这种重复区分和渲染可能是任何React应用程序中React性能问题的主要来源之一。 在差异化算法无法有效协调的情况下构建React应用程序,导致整个应用程序被重复渲染,这实际上导致浪费的渲染,并可能导致令人沮丧的缓慢体验。

During the initial render process, React builds a DOM tree like this —

在初始渲染过程中,React会像这样构建DOM树-

Suppose that a part of the data changes. What we want React to do is re-render only the components that are directly affected by that specific change. Possibly skip even the differentiating process for the rest of the components. Let’s say some data changes in Component 2 in the above picture, and that data has been passed from R to B and then 2. If R re-renders then it’ll re-render each of its children that means A, B, C, D and by this process what actually React does is this:

假设一部分数据发生了变化。 我们希望React要做的是仅重新渲染受该特定更改直接影响的组件。 甚至可以跳过其余组件的区分过程。 假设上图中的组件2中有一些数据更改,并且该数据已从R传递到B ,然后传递到2 。 如果R重新渲染,那么它将重新渲染它的每个子元素,这意味着A,B,C,D,并且通过此过程,React实际执行的操作是:

In the image above, all the yellow nodes are rendered and differentiated. This results in wasted time/computation resources. This is where we will primarily put our optimization efforts. Configuring each component to only render and differentiate when it is necessary. This will allow us to reclaim those wasted CPU cycles. First, we’ll take a look into the way that we can identify wasted renders of our application.

在上图中,所有黄色节点都被渲染和区分。 这导致浪费时间/计算资源。 这是我们主要进行优化工作的地方。 配置每个组件以仅在必要时进行渲染和区分。 这将使我们能够回收那些浪费的CPU周期。 首先,我们将研究确定应用程序浪费的渲染的方式。

识别浪费的渲染 (Identify wasted renders)

There are a few different ways to do this. The simplest method is to toggle on the highlight updates option in the React dev tools preference.

有几种不同的方法可以做到这一点。 最简单的方法是在React开发工具首选项中打开突出显示更新选项。

While interacting with the app, updates are highlighted on the screen with colored borders. By this process, you should see components that have re-rendered. This lets us spot re-renders that were not necessary.

与应用程序交互时,更新会在屏幕上以彩色边框突出显示。 通过此过程,您应该看到已重新渲染的组件。 这使我们可以发现不必要的重新渲染。

Let’s follow this example.

让我们跟随这个例子。

Note that when we’re entering a second todo, the first ‘todo’ also flashes on the screen on every keystroke. This means it is being re-rendered by React together with the input. This is what we are calling a “wasted” render. We know it is unnecessary because the first todo content has not changed, but React doesn’t know this.

请注意,当我们输入第二个待办事项时,每次按键时,第一个“待办事项”也会在屏幕上闪烁。 这意味着它将由React与输入一起重新渲染。 这就是我们所谓的“浪费”渲染。 我们知道这是没有必要的,因为第一个待办事项内容没有更改,但是React不知道这一点。

Even though React only updates the changed DOM nodes, re-rendering still takes some time. In many cases, it’s not a problem, but if the slowdown is noticeable, we should consider a few things to stop those redundant renders.

即使React仅更新已更改的DOM节点,但重新渲染仍需要一些时间。 在很多情况下,这不是问题,但是如果速度下降明显,我们应该考虑一些事情来停止那些多余的渲染。

使用shouldComponentUpdate方法 (Using shouldComponentUpdate method)

By default, React will render the virtual DOM and compare the difference for every component in the tree for any change in its props or state. But that is obviously not reasonable. As our app grows, attempting to re-render and compare the entire virtual DOM at every action will eventually slow the whole thing down.

默认情况下,React将渲染虚拟DOM并比较树中每个组件的差异,以了解其属性或状态的任何变化。 但这显然是不合理的。 随着我们的应用程序的增长,在每次操作时尝试重新渲染和比较整个虚拟DOM最终都会使整个过程变慢。

React provides a simple lifecycle method to indicate if a component needs re-rendering and that is, shouldComponentUpdate which is triggered before the re-rendering process starts. The default implementation of this function returns true.

React提供了一个简单的生命周期方法来指示组件是否需要重新渲染,即应该在重新渲染过程开始之前触发的shouldComponentUpdate 。 该函数的默认实现返回true

When this function returns true for any component, it allows the render differentiating process to be triggered. This gives us the power of controlling the render differentiating process. Suppose we need to prevent a component from being re-rendered, we need simply to return false from that function. As we can see from the implementation of the method, we can compare the current and next props and state to determine whether a re-render is necessary:

当此函数对任何组件返回true时,它将允许渲染区分过程被触发。 这使我们能够控制渲染差异化过程。 假设我们需要防止组件被重新渲染,我们只需要从该函数返回false即可。 从该方法的实现中可以看出,我们可以比较当前和下一个道具和状态,以确定是否需要重新渲染:

使用纯组件 (Using pure components)

As you work on React you definitely know about React.Component but what’s the deal with React.PureComponent? We’ve already discussed shouldComponentUpdate lifecycle method, in pure components, there is already a default implementation of, shouldComponentUpdate() with a shallow prop and state comparison. So, a pure component is a component that only re-renders if props/state is different from the previous props and state.

在工作过程中上React你肯定知道React.Component但什么是该交易的React.PureComponent ? 我们已经讨论了shouldComponentUpdate生命周期方法,在纯组件中,已经有默认的shouldComponentUpdate()实现,带有浅层shouldComponentUpdate()和状态比较。 因此,纯组件是仅在props/state与先前的propsstate不同的情况下才重新渲染的组件。

In shallow comparison, primitive data-types like string, boolean, number are being compared by value and complex data-types like array, object, function are compared by reference
在浅层比较中,原始数据类型(例如字符串,布尔值,数字)通过值进行比较,而复杂数据类型(例如数组,对象,函数)通过​​引用进行比较

But, what if we have a functional stateless component in which we need to implement that comparison method before each re-rendering happens? React has a Higher Order Component React.memo. It is like React.PureComponent but for functional components instead of classes.

但是,如果我们有一个功能性的无状态组件,该组件需要在每次重新渲染发生之前实现该比较方法,该怎么办? React有一个更高阶的组件React.memo 。 它类似于React.PureComponent但用于功能组件而不是类。

By default, it does the same as shouldComponentUpdate() which only shallowly compares the props object. But, if we want to have control over that comparison? We can also provide a custom comparison function as the second argument.

默认情况下,它的作用与shouldComponentUpdate()相同,后者仅浅层比较props对象。 但是,如果我们想控制该比较? 我们还可以提供自定义比较功能作为第二个参数。

使数据不变 (Making Data Immutable)

What if we could use a React.PureComponent but still have an efficient way of telling when any complex props or states like an array, object, etc. have changed automatically? This is where the immutable data structure makes life easier.

如果我们可以使用React.PureComponent但仍然有一种有效的方式来告知任何复杂的道具或状态(例如数组,对象等)何时自动更改怎么办? 这是不可变数据结构使生活更轻松的地方。

The idea behind using immutable data structures is simple. As we’ve discussed earlier, for complex data-types the comparison performs over their reference. Whenever an object containing complex data changes, instead of making the changes in that object, we can create a copy of that object with the changes which will create a new reference.

使用不可变数据结构的想法很简单。 如前所述,对于复杂的数据类型,比较将在其引用上进行。 每当包含复杂数据的对象发生更改时,我们无需在该对象中进行更改,而可以使用更改创建该对象的副本,这将创建一个新引用。

ES6 has object spreading operator to make this happen.

ES6具有对象散布算子以实现此目的。

We can do the same for arrays too:

我们也可以对数组做同样的事情:

避免为相同的旧数据传递新的引用 (Avoid passing a new reference for the same old data)

We know that whenever the props for a component changes, a re-render happens. But sometimes the props didn’t change. We write code in a way that React thinks it did change, and that’ll also cause a re-render but this time it’s a wasted render. So, basically, we need to make sure that we’re passing a different reference as props for different data. Also, we need to avoid passing a new reference for the same data. Now, we’ll look into some cases where we’re creating this problem. Let’s look at this code.

我们知道,每当props的成分变化,重新绘制发生。 但是有时候props没有变。 我们以React认为确实有所改变的方式编写代码,这也会导致重新渲染,但是这次是浪费的渲染。 因此,基本上,我们需要确保传递不同的参考作为支持不同数据的道具。 同样,我们需要避免传递相同数据的新引用。 现在,我们将研究造成这种问题的某些情况。 让我们看一下这段代码。

Here’s the content for the BookInfo component where we’re rendering two components, BookDescription and BookReview. This is the correct code, and it works fine but there is a problem. BookDescription will re-render whenever we get new reviews data as props. Why? As soon as the BookInfo component receives new props, the render function is called to create its element tree. The render function creates a new book constant that means a new reference is created. So, BookDescription will get this book as a news reference, that’ll cause the re-render of BookDescription. So, we can refactor this piece of code to this:

这是BookInfo组件的内容,我们在其中渲染两个组件BookDescriptionBookReview 。 这是正确的代码,可以正常工作,但是存在问题。 每当我们获得新的评论数据作为道具时, BookDescription将重新呈现。 为什么? 一旦BookInfo组件收到新的道具,就会调用render函数来创建其元素树。 render函数创建一个新的book常量,这意味着将创建一个新的引用。 因此, BookDescription将把这book作为新闻参考,这将导致BookDescription的重新呈现。 因此,我们可以将这段代码重构为:

Now, the reference is always the same, this.book and a new object isn’t created at render time. This re-rendering philosophy applies to every prop including event handlers, like:

现在,引用始终是相同的, this.book和渲染时不会创建新对象。 这种重新渲染的理念适用于包括事件处理程序在内的每个prop ,例如:

Here, we’ve used two different ways (binding methods and using arrow function in render) to invoke the event-handler methods but both will create a new function every time the component re-renders. So, to fix these issues, we can bind the method in the constructor and using class properties which is still in experimental and not standardized yet but so many devs are already using this method of passing functions to other components in production ready applications:

在这里,我们使用了两种不同的方式(绑定方法和在render中使用arrow函数)来调用事件处理程序方法,但是每次组件重新渲染时,这两种方法都会创建一个新函数。 因此,要解决这些问题,我们可以将方法绑定到constructor并使用仍在实验中且尚未标准化的类属性,但是许多开发人员已经在使用此方法将功能传递给生产就绪应用程序中的其他组件:

结语 (Wrapping up)

Internally, React uses several clever techniques to minimize the number of costly DOM operations required to update the UI. For many applications, using React will lead to a fast user interface without doing much work to optimize for performance specifically. Nevertheless, if we can follow the techniques I’ve mentioned above to resolve wasted renders then for large applications we’ll also get a very smooth experience in terms of performance.

在内部,React使用几种巧妙的技术来最小化更新UI所需的昂贵的DOM操作的数量。 对于许多应用程序而言,使用React将导致快速的用户界面,而无需进行大量工作来专门针对性能进行优化。 但是,如果我们可以遵循上面提到的技术来解决浪费的渲染,那么对于大型应用程序,我们还将在性能方面获得非常流畅的体验。

翻译自: https://www.freecodecamp.org/news/how-to-identify-and-resolve-wasted-renders-in-react-cc4b1e910d10/

react 中渲染html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值