Improving Performance in React Functional Component using React. Memo Improving Performance in React Functional Component using React. This article describes how to use shouldComponentUpdate lifecycle function and PureComponent to avoid useless rerendering of class components when developing React applications, and how to use the latest React. Memo API to optimize the performance of function components.

The React core development team has been working hard to make React faster. There are several ways to optimize component performance in React:

  • Component lazy loading (React. Lazy (…)) And < Suspense / >)
  • Pure Component
  • shouldComponentUpdate(…) {… } Life cycle functions

This article also introduces another method added to React16.6 specifically to optimize the performance of Functional components: react.Memo.

Useless rendering

Components are the basic unit that makes up the React view. Some components have their own local states, and when their values change due to user action, the components are rerendered. In a React application, a component might be rendered frequently. A few of these renders are necessary, but most are useless, and their presence can significantly degrade the performance of our application.

Look at this example:

import React from 'react';

class TestC extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }
    
    componentWillUpdate(nextProps, nextState) {
        console.log('componentWillUpdate')
    }
    
    componentDidUpdate(prevProps, prevState) {
        console.log('componentDidUpdate')}render() {
        return( <div > {this.state.count} <button onClick={()=>this.setState({count: 1})}>Click Me</button> </div> ); }}export default TestC;
Copy the code

The TestC component has a local state count with an initial value of 0(state = {count: 0}). When we Click the Click Me button, the value of count is set to 1. The number on the screen will change from 0 to 1. When we click the button again, count is still 1, and the TestC component should not be rerendered, but is that the case?

To test whether components that repeatedly set count to the same value will be rerendered, I added two life cycle functions to the TestC component: componentWillUpdate and componentDidUpdate. The componentWillUpdate method is called when the component is about to be rerendered, while the componentDidUpdate method is called after the component has been successfully rerendered.

Run our code in a browser and Click the Click Me button several times. You can see the following output:

Pure Component/shouldComponentUpdate

To avoid useless rendering of the React component, we can implement our own shouldComponentUpdate lifecycle function.

When React wants to render a component, it will call the component’s shouldComponentUpdate function, which tells it if it really wants to render the component.

If our shouldComponentUpdate function is written like this:

shouldComponentUpdate(nextProps, nextState) {
    return true        
}
Copy the code

The meanings of each parameter are as follows:

  • nextProps: The next parameter that the component will receive
  • nextProps: The next state of the componentstate

Since our shouldComponentUpdate function keeps returning true, this tells React to rerender the component in any case.

But if we write this:

shouldComponentUpdate(nextProps, nextState) {
    return false
}
Copy the code

Because this method returns false, React will never re-render our component.

So when you want React to re-render your components, return true in this method, otherwise return false. Now let’s rewrite the previous TestC component with shouldComponentUpdate:

import React from 'react';

class TestC extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }
    
    componentWillUpdate(nextProps, nextState) {
        console.log('componentWillUpdate')
    }
    
    componentDidUpdate(prevProps, prevState) {
        console.log('componentDidUpdate')
    }
    
    shouldComponentUpdate(nextProps, nextState) {
        if (this.state.count === nextState.count) {
            return false
        }
        return true
    }
    
    render() {
        return( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div> ); }}export default TestC;
Copy the code

We added a shouldComponentUpdate method to TestC to determine if the count in the current state is the same as the count in the next state. This way React will not rerender the component. Instead, if the two values are different, Return true, and the component will be re-rendered.

Testing our component again in the browser, the initial interface looks like this:

At this point, even if we Click the Click Me button many times, we only get two lines of output:

componentWillUpdate
componentDidUpdate 
Copy the code

Because count is always 1 after the second Click on the Click Me button, shouldComponentUpdate always returns false, so the component is no longer rerendered.

How do you verify that the value of state changes later and the component is rerendered? You can change the state of the TestC component directly in the React DevTools plug-in of your browser. In the Chrome debugger, click the React TAB and select the TestC component on the left. On the right side of the screen, you can see that its state contains only one key, count, and its value is 1:

componentWillUpdate
componentDidUpdate
componentWillUpdate
componentDidUpdate
Copy the code

The count of state has been changed and the component has been re-rendered.

Now let’s use another method, PureComponent, to optimize the component.

React introduced the Pure Component in V15.5. React performs a shallow comparison of the component’s current state and props to its next state and props if the component is a PureComponent. If their values have not changed, the component will not be updated. To make your Component PureComponent, just extends React.PureComponent.

Let’s rewrite our code with PureComponent:

import React from 'react';

class TestC extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }
    
    componentWillUpdate(nextProps, nextState) {
        console.log('componentWillUpdate')
    }
    
    componentDidUpdate(prevProps, prevState) {
        console.log('componentDidUpdate')
    }
    
    /*shouldComponentUpdate(nextProps, nextState) {
        if (this.state.count === nextState.count) {
            return false
        }
        return true} * /render() {
        return( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div > ); }}export default TestC;
Copy the code

In the code above, I commented out shouldComponentUpdate because the React.PureComponent does the same thing for us.

After changing the code, we refresh the browser and Click the Click Me button several times to see how many times the component has been rendered:

Function component

Above we looked at how to optimize the performance of class components using the PureComponent and shouldComponentUpdate methods. Although classes are a major part of the React application, Functional components can also be used as React components.

function TestC(props) {
    return (
        <div>
            I am a functional component
        </div>
    )
}
Copy the code

For function components, They don’t have anything like state to hold their local state (although function components in React Hooks can use useState to useState), so we can’t control the rerendering of function components like shouldComponentUpdate in class components. Of course, we can’t use extends React.PureComponent because it’s not a class at all.

To explore a solution, let’s first verify that function components have the same useless rendering problem as class components.

TestC: ES6 TestC: ES6 TestC

import React from 'react';

const TestC = (props) => {
    console.log(`Rendering TestC :` props)
    return ( 
        <div>
            {props.count}
        </div>
    )
}
export default TestC;
// App.js
<TestC count={5} />
Copy the code

When the above code first loads, the console output is:

Since function components also have the problem of useless rendering, how can we optimize them?

Solution: Use react.Memo ()

React.memo(…) React v16.6 is a new property. It acts like the React.PureComponent, controlling the re-rendering of function components. React.memo(…) This is the react. PureComponent of the function component.

How to use react.Memo (…) ?

React.memo is very simple to use, assuming you have the following function components:

const Funcomponent = ()=> {
    return (
        <div>
            Hiya!! I am a Funtional component
        </div>
    )
}
Copy the code

We simply pass the above Funcomponent as an argument to React. Memo:

const Funcomponent = ()=> {
    return (
        <div>
            Hiya!! I am a Funtional component
        </div>
    )
}
const MemodFuncComponent = React.memo(FunComponent)
Copy the code

React. Memo returns a Purified MemoFuncComponent that will be rendered in the JSX tag. React checks if the props and state of the component are the same as the next. If they are the same, the component will not be rendered; if they are different, the component will be rendered again.

Now let’s optimize the TestC component using react. memo:

let TestC = (props) => {
    console.log('Rendering TestC :', props)
    return ( 
        <div>
        { props.count }
        </>
    )
}
TestC = React.memo(TestC);
Copy the code

Open your browser and reload our app. Then open the Chrome debugger, click the React TAB, and select the

component.
(testc)>

Then edit the props and change count to 89, and we’ll see our application rerendered:

This is the React. Memo (…). This function is awesome in X place!

The one before us didn’t use React. Memo (…) In this example, the repeated setting of count causes the component to be rerendered. When we use React. Memo, the component will not be rerendered if the values passed in remain unchanged.

conclusion

Here are some summary points:

  • React.PureComponentIs silver
  • React.memo(...)Is gold
  • React.PureComponentIs used for ES6 class components
  • React.memo(...)Is used by function components
  • React.PureComponentReduce useless rendering of ES6 class components
  • React.memo(...)Reduce useless rendering of function components
  • Providing optimization for functional components is a huge step forward

I am the green onion, pay attention to my public account, get the latest technology push I share!