React organizes logic in the form of components, which allow us to break the UI into individual reusable code fragments and think about each fragment independently. Therefore, React has some performance optimization ideas full of its own characteristics, which are basically developed around the central idea of “component performance optimization” : optimization is mainly carried out in the following three aspects

  • Use shouldComponentUpdate to avoid repeated renderings
  • Using PureComponent
  • Use the React. Memo and useMemo cache components

shouldComponentUpdate

ShouldComponentUpdate is a lifecycle of the React class component. ShouldComponentUpdate: functions (props), functions (state), functions (functions), functions (functions), functions (functions), functions (functions), functions (functions) and functions (functions)

shouldComponentUpdate(nextProps, nextState)
Copy the code

In React, many times we will inadvertently frequently call render. To avoid the performance overhead of unnecessary Render operations, React provides a shouldComponentUpdate cycle in which we can predict whether subsequent cycles need to be executed.

So just to see what’s going on, let’s write a demo to see what’s going on

Here we write two components and one parent: childa.js

import React from "react"; Export Default class ChildA extends React.Com {render () {console.log("ChildA's render method executes "); Return (<div> the contents of the child component A: {this.props. Text} </div>); }}Copy the code

Here childb.js is similar to childA: show different text, then put childA and childB into parent app.js:

import React from "react"; import ChildA from './ChildA' import ChildB from './ChildB' class App extends React.Component { state = { textA: } changeA = () => {this.setstate ({textA: } changeB = () => {this.setstate ({textB: Render () {return (<div className="App"> <div className="container"> <div className=" buttons "> <div className='buttons' onClick={this.changea}> <div className='buttons' onClick={this.changeb}> <div > <ul> <li> <ChildA  text={this.state.textA}/> </li> <li> <ChildB text={this.state.textB}/> </li> </ul> </div> </div> ); } } export default App;Copy the code

Running the code, we find that group A has rendered both component B and component A, and the result is as follows:

Next, click buttons to change the props text in the child component. The result is as follows:We’ll see that if we click on the first button, we’ll change the props text for component A, and component B will render it again.

In React, whenever a parent component is updated, all child components are updated unconditionally. This causes component B’s props to go through the update process even though nothing has changed and it doesn’t have any points to be updated.

The same applies to updates to the component itself: when a setState is called by the component itself, the state content before and after the setState is rerendered regardless of whether it has actually changed.

Set shouldComponentUpdate for data determination

ShouldComponentUpdate (newProps, newStates) {// Check if the text property has changed before or after the parent component update. If (this.props. Text === newProps. Text) {return false} return true}Copy the code

ShouldComponentUpdate acts as a component guard when the parent App component is updated, triggering the childB update process: It will check to see if the newly updated props. Text is the same as the previous one. If it is, then it will not execute the periodic function and simply return “false” to interrupt the entire childB lifecycle. Only if the props. Text changes will it continue the lifecycle and re-render the component.

After shouldComponentUpdate is set, click the Update button again to modify childA’s render content. Let’s see what the render results look like:

Here, we click the button of “modify A”. After clicking, we find that the component of childA has been modified, and childB has not been re-rendered, which avoids unnecessary rendering. ShouldComponentUpdate is used for comparison to make unnecessary update and avoid meaningless rendering. This is the most basic performance optimization approach in the React component, and the most important one.

PureComponent

ShouldComponentUpdate helps us solve the performance problem, but it’s a little cumbersome to implement shouldComponentUpdate manually every time you compare.

We can wrap it as a component, which will greatly avoid having to write shouldComponentUpdate multiple times

React has a PureComponent class that solves the problem of writing shouldComponentUpdate multiple times.

Let’s try it out using PureComponent

Export Default class ChildA extends React.pureComponent {render () {console.log("ChildB's render method executes "); Return (<div> child component B: {this.props. Text} </div>); }}Copy the code

And then I’m gonna go ahead and hit modify A, and I’m going to get A pretty good result, which is pretty much the same as shouldComponentUpdate,

It quickly becomes apparent that the PureComponent only works for value applications, and when object applications don’t work, it will be rerendered

changeA = () => { console.log('xhiiang'); let { personA } = this.state personA.name = 'ZLP' this.setState({ personA, })} export default class ChildA extends React.pureComponent {render () {console.log("ChildB's render method executes "); {this.props. Text} {this.props. PersonA} </div>); }}Copy the code

PureComponent vs. Component: PureComponent will perform a shallow comparison of props and states before and after the component is updated in shouldComponentUpdate and determine whether to continue the update process based on the results.

So when you click on the modify data, the components are not rerendered because they are lightly compared and referenced the same

The React. The memo and userMemo

Memo is a top-level function exported from React, which is essentially a high-level component that wraps function components.

import React from "react"; Function childA (props) {console.log(" childA's render method executed "); Return (<div> child component A: {props. Text} </div>); } function areEqual (prevProps, props) nextProps) { if (prevProps.text === nextProps.text) { return true } return false } export default React.memo(childA, areEqual)Copy the code

The execution result is as follows:

Similarly, the array of components A and B is not changed and will not reproduce the render

Memo takes two arguments. The first argument is the component we want to render, and the second argument is the comparison logic for props. Everything we did in the shouldComponentUpdate, we can now do in the second argument

Of course you don’t have to write the second argument, but it will make a shallow comparison to the props of your component

useMemo

Memo controls whether a component needs to be rerendered, while useMemo controls whether a piece of logic needs to be executed repeatedly.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Copy the code

We can pass in the target logic as the first argument and the array of dependencies for that logic as the second argument. UseMemo will then re-execute the target logic in the first input only if one of the dependencies in the dependency array changes.

import React, { useMemo } from "react"; Export default function ChildB ({text, count}) {console.log("ChildB component render execution "); Const renderText = (text) => {console.log('renderText executed ') return <p> The text content of subcomponent B: Const renderCount = (count) => {console.log('renderCount executed ') return <p> Const textContent = useMemo(() => renderText(text), [text]) const countContent = useMemo(() => renderCount(count), [count]) return ( <div className="childB"> {textContent} {countContent} </div> ); State = {textA: 'I'm A', stateB: {text:' I'm A', count: }} changeA = () => {this.setstate ({textA:' A'})} changeB = () => {this.setstate ({stateB: {... this.state.stateB, count: 100 } }) }Copy the code

After using useMome, look at the results:

For the first render, both textContent and countContent are executed,

Then we click to modify the text of component A, and the operation result is as follows:

You will see that the refined textContent and countContent are not rerendered; component B is rendered

Then click to change the count of b, and the execution result is as follows:

This time, component B is rerendered, countContent is rerendered, and textContent is not rerendered because the text has not changed

Use userMemo for a more detailed comparison of components. Made up for the inability of React.memo to sense the internal state of functions

Code word is not easy, hope big guy give directions!