Preface:
React is a JAVASCRIPT library for building user interfaces. Mainly used for building UI, many people think of React as the V (view) in MVC.
react uses virtual DOM technology to reduce the interaction between Javascript and the real DOM, improving front-end performance; using a one-way data flow mechanism, the parent component passes data to the child component through props, so that the data flow direction is clear at a glance.
Once the props or state of the component change, the component and its subcomponents will re-render and vdom-diff to complete the data flow interaction. However, this mechanism may have some performance problems in some cases, such as when the amount of data is large. Let's analyze the performance bottlenecks of react, and use the react-addons-perf tool to illustrate the importance of react component splitting.
react performance bottleneck
To understand the performance bottleneck of react, you need to know the rendering process of react. Its rendering can be divided into two stages:
Initial componentization
This stage will execute the render method of the component and all its subcomponents, thereby generating the first version of the virtual dom.
Component update rendering.
Any change in the props or state of the component will trigger the update rendering of the component. By default, it will also execute the render method of the component and all its subcomponents to obtain the new virtual DOM.
The performance bottleneck we are talking about refers to the situation during the component update phase.
react component update process
Through the above analysis, we can know that the specific process of component update is as follows:
Execute the render method of the component and all its subcomponents to obtain the updated virtual DOM , that is, re-render, even if the child component does not need to be updated.
Then diff the old and new virtual DOM to update the component
In this process, you can determine whether re-render is required through the return value of the component's shouldComponentUpdate method.
The entire update rendering process of React can be explained with a picture:
By default, the component's shouldComponentUpdate returns true, that is, React will call it by default The render method of all components generates a new virtual DOM, and then compares it with the old virtual DOM to determine whether the component ultimately needs to be updated.
react performance bottleneck
Let’s talk with a picture. For example, the picture below is a component structure tree. When we want to update a sub-component, the green component in the picture below (passed from the root component to the application The data on the green component changes):
Ideally, we only want the components on the critical path to be updated, as shown below:
However, the actual effect is that each component completes the re-render and virtual-DOM diff process, although the component has not changed, which is obviously a waste. As shown in the figure below, the yellow part represents wasted re-render and virtual-DOM diff.
According to the above analysis, the performance bottleneck of react is mainly manifested in:
For components whose props and state have not changed, react also needs to regenerate the virtual DOM. and virtual DOM diff.
Use shouldComponentUpdate for performance optimization
In response to the performance bottleneck of react, we can use the shouldComponentUpdate method provided by react to do some optimization. We can selectively update components to improve react. The performance is as follows:
shouldComponentUpdate needs to determine whether the current properties and status are the same as the last time. If they are the same, there is no need to perform the subsequent process of generating virtual DOM and its diff, otherwise it needs to be updated.
(Learning video sharing: javascript video tutorial)
The specific implementation can be displayed as follows:
shouldComponentUpdate(nextProps, nextState){ return !isEqual(nextProps, this.props) || !isEqual(nextState, this.state) }
Among them, the isEqual method is to determine whether two objects Equality (refers to the fact that the contents of its objects are equal, not congruent).
Determine whether the component needs to be updated by displaying the override shouldComponentUpdate method to avoid useless updates. However, adding this method to each component will be cumbersome. Fortunately, react provides an official solution. The specific method is:
The solution encapsulates the component's shouldComponentUpdate and implements a shallow comparison of the component's current properties and status with the previous one to determine whether the component needs to be updated.
react provides two sets of official solutions at different stages of development:
PureRenderMin
One is a component created based on ES5's React.createClass, which is combined with the mixins method in this form. shouldComponentUpdate method provided by PureRenderMixin. Of course, components created with ES6 can also use this solution.
PureComponent
This solution is a component base class added for ES6 released in React 15.3.0 version: React.PureComponent. This is obviously more friendly to components created in ES6 way.
It should be pointed out that whether it is PureRenderMin or PureComponent, their internal shouldComponentUpdate method shallowly compares (shallowCompare) props and state objects, that is, only compares the first object of the object. Whether the attributes and their values of one layer are the same. For example, the following state object is changed to the following value:
Because the value of state is assigned to another object, nextState.value and this.props.value are always not equal, resulting in shallow The comparison failed. In actual projects, this kind of nested object result is very common. If the PureRenderMin or PureComponent method is used, the desired effect will not be achieved.
Although it can be judged through deep comparison, deep comparison is similar to deep copy, a recursive operation, and the performance overhead is relatively large.
To this end, you can split the components as much as possible to flatten the component's props and state object data. Combined with using PureRenderMin or PureComponent to determine whether the component has been updated, you can better improve the performance of react. , does not require developers to care too much.
Component splitting
Component splitting, in react, is to subdivide components as much as possible to facilitate reuse and optimization. The specific principles of splitting:
Try to make it easier for the split components to determine whether to update
This is not easy to understand. Let’s give an example: Suppose we define a parent component that contains 5000 sub-components. There is an input box input operation. Every time a number is entered, the background color of the corresponding subcomponent turns red.
In this example, the input box component and the list subcomponent are obviously different. One is dynamic, and input values are more frequent; the other is relatively static, regardless of the input. Enter it is 5000 items. Every time a number is entered into the input box, all components will be re-rendered, which will cause unnecessary updates to the list sub-components.
It can be seen that the update of the list component above is not easy to cancel, because the state of the input component and the list subcomponent are placed in the parent component state, and they are shared; it is impossible for react to use the return value of shouldComponentUpdate. Make one part of the component update and the other part not. Only by splitting them into different components, each component only cares about the corresponding props. The split list component only cares about its own attributes, and other components cause the update of the parent component. In the list component, you can decide whether to update by judging the value of the attributes you care about, so that you can better optimize the component.
Try to flatten the props and state data of split components
This is mainly considered from the perspective of component optimization. If the component does not need to pay too much attention to performance, it can be ignored.
The reason why split components are flat is because the optimization solution PureRenderMin or PureComponent provided by React shallowly compares the props and state of the component to decide whether to update the component.
In the list component above, this.state.items stores an array of objects. In order to better judge whether each list needs to be updated, each li list item can be split into a list item component. , the props related to each list item are each object in the items array. This flat data makes it easy to determine whether the data has changed.
An example of component splitting
For this article, I wrote a case library about adding and displaying Todo lists. Clone the code locally to run the effect locally.
The case library is a Todo list with 5,000 items, and Todo items can be deleted and added. This example shows the comparison of experience before and after component splitting, and it can be seen that there is a significant improvement in performance.
Below we combine the react-addons-perf performance testing tool to illustrate the component splitting situation.
The render part of the component TodosBeforeDivision before splitting is as follows:
Before the component is split, you can enter characters in the input box, add todo or delete todo items. It can be seen that there is obvious lag, as shown in the following figure:
#In order to find out what causes the lag, we use chrome's devTool to locate it. The method is to use the Performance option of the latest version of the chrome browser. First click the record button in this option to start recording. At this time, we enter a character in the component input box, and then click stop to stop recording. We will see a performance profile of the component from the beginning to the end of the input.
As can be seen from the figure, when we enter a single character, the input event logic of the input box takes up almost the entire response time. The specific processing logic is mainly the batchedUpdates method at the react level. Update list components in batches instead of user-defined logic.
So, why does batch update take so much time? In order to understand the reason, we use the chrome plug-in chrome-react-perf based on react-addons-perf, which outputs the analysis results in the form of a chrome plug-in. .
One thing to note when using this plug-in is:
The use of the chrome-react-perf plug-in requires the introduction of the react-addons-perf module into the project, and its object must be mounted to the window On the Perf attribute of the global object, otherwise it cannot be used.
Select the Perf option view in the devTool tool, click the start button and it will become the stop button, enter a character in the component input box, and then click the stop button in the Perf view, you will get the corresponding performance attempt.
Among the four views provided in the above figure, Print Wasted is the most helpful for analyzing performance. It indicates that the component has not changed but participated in the update process, that is, wasted re- The process of render and vdom-diff is a meaningless process. As can be seen from the figure: TodosBeforeDivision and TodoItem components wereted 167.88ms and 144.47ms respectively. This overhead can be avoided by splitting the components. This is the focus of react performance optimization.
For this we need to split the TodosBeforeDivision component into a dynamic component AddTodoForm with input and button and a relatively static component TodoList. Both inherit React.PureComponent respectively to avoid unnecessary component updates.
The TodoList component also needs to be split into a component TodoItem for each Todo task, so that the props object of each TodoItem component is flat data, and React can be fully utilized .PureComponent is used to perform a shallow comparison of objects to better determine whether the component needs to be updated. This avoids the need to update other TodoItem components when a TodoItem item is added or deleted.
After splitting the components in this way, use the above performance testing tool to check the corresponding effect:
From As can be seen from the screenshot above, the performance of the split component has been improved hundreds of times, although it also includes some other optimizations, such as not binding this to the component attribute position and caching constant object props to avoid re -Regenerate new functions and new object props when -rendering.
In general, splitting react components is very important to improve react performance. This is also a direction for react performance optimization.
Related recommendations: react tutorial
The above is the detailed content of The importance of splitting react components. For more information, please follow other related articles on the PHP Chinese website!