First of all, welcome everyone to pay attention to my Github blog, which can also be regarded as a little encouragement to me. It is my own enthusiasm and everyone’s encouragement that can persist. I hope everyone pays more attention to it! The React section continues to be updated…

React15.3 adds a PureComponent class to replace PureRenderMixin. PureComponent optimizes React performance to reduce unnecessary render times. Simply change the inherited class from Component to PureComponent.

PureComponent inherits the Component class and automatically loads shouldComponentUpdate. When a Component is updated, shouldComponentUpdate performs a shallow comparison between props and state. If the props and state of the component are not changed, the Render method will not trigger, saving the Virtual DOM generation and comparison process to improve performance.

Let’s look at PureComponent thoroughly from its use and source code.

ShouldComponentUpdate optimizes performance

Before PureComponent, we often saw that one of the most common ways to optimize react performance was to check whether the props or state data changed in the React lifecycle function shouldComponentUpdate. Prevent unnecessary render by returning true (update) and false(not update).

First let’s look at a scene where React renders unnecessarily:

Use create-react-app to initialize the react runtime environment and create a scheduled task in app.js that updates the data every second:

import React, { Component } from 'react'
import ShouldComponentUpdateList from './ShouldComponentUpdateList'

// Container components
export default class App extends Component {
    state = {
        data: []}componentDidMount() {
        // Scheduled task, update data every second
        setInterval(() = > {
            this.setState({
                data: [{title: 'react line 1' }, 
                    { title: 'react line 2'},]})},1000)}render() {
        return(
            <div>
                {
                    this.state.data.map((item, index) => (
                        <ShouldComponentUpdateList key={index} list={item} />))}</div>)}}Copy the code

ShouldComponentUpdateList component content as follows:

export default class List extends Component {
    render() {
        console.log('list render')
        return(
            <div>{this.props.list.title}</div>)}}Copy the code

Run the NPM start command line to check the output of the browser:

The console will print list render every second, but react still render, causing unnecessary waste of rendering.

Just add a judgment to shuoldComponentUpdate and check the output again. The data of the scheduled task is not changed and the render function is no longer used:

export default class List extends Component {
    // In shuoldComponentUpdate, render is not required to render the props
    shouldComponentUpdate(nextProps) {
        // return true to render, false to render
        if(nextProps.list.title === this.props.list.title) {
            return false
        }
        return true
    }
    render() {
        console.log('list render')
        return(
            <div>{this.props.list.title}</div>)}}Copy the code

PureComponent use

Instead of using shouldComponentUpdate to determine if a component needs to be updated, you can also use PureComponent. PureComponent actually automatically loads shouldComponentUpdate. When a component is updated, ShouldComponentUpdate makes a shallow comparison between props and state.

Create a PureComponentList Component and replace Component with PureComponent:

import React, { PureComponent } from 'react'
export default class List extends PureComponent {
    render() {
        console.log('list render')
        return(
            <div>{this.props.list.title}</div>)}}Copy the code

Pass in the App component:

this.state.data.map((item, index) = > (
    <PureComponentList key={index} list={item}/>
))
Copy the code

Then you look at the browser output and, to your surprise, PureComponent doesn’t prevent unnecessary render. Why? The PureComponent shouldComponentUpdate only compares props to state. This. Props = {list: {title: ‘react line1’}}, nextProps = {list: {title: ‘react line1’}}, this.

To see why more clearly, let’s take a look at the PureComponent source code.

PureComponent source

Start with the PureComponent function, which inherits Component properties and methods from the constructor and prototype, respectively:

export default function PureComponent(props, context) {
    Component.call(this, props, context)
}

PureComponent.prototype = Object.create(Component.prototype)
PureComponent.prototype.constructor = PureComponent
PureComponent.prototype.shouldComponentUpdate = shallowCompare

function shallowCompare(nexProps, nextState) {
    return! shallowEqual(this.props, nextProps) || ! shollowEqual(this.state, nextState)
}
Copy the code

The PureComponent then writes the shallowCompare method inside the lifecycle function. ShallowCompare returns true or false from shallowEqual.

ShallowEqual (shallowEqual);

export default function shallEqual(objA, objB) {
    // The comparison between two objects is as follows
    if (objA === objB) {
        return true;
    }

    if (typeofobjA ! = ='object' || objA === null ||
        typeofobjB ! = ='object' || objB === null) {
        return false;
    }

    const keysA = Object.keys(objA);
    const keysB = Object.keys(objB);

    if(keysA.length ! == keysB.length) {return false;
    }

    // Test for A's keys different from B.
    for (let i = 0; i < keysA.length; i++) {
        if(! objB.hasOwnProperty(keysA[i]) || objA[keysA[i]] ! == objB[keysA[i]]) {return false; }}return true;
}
Copy the code

If (objA === objB) {return true; } let a = {list: {title: ‘react line1′}} let b = {list: {title: {react line1’}} ‘react line1’}}, a === b has a value of false, so this is a good explanation for why the above PureComponent does not prevent unnecessary render.

So let’s improve the code to make sure that PureComponent props work if passed objects:

Change PureComponentList in app.js to pass item.title instead of item. The browser only prints log twice:

this.state.data.map((item, index) = > (
    // <PureComponentList key={index} list={item}/>
    <PureComponentList key={index} title={item.title}/>
))
Copy the code

We optimize unnecessary rendering by deconstructing the item object and passing in item.title so that shallow comparisons can be made.

The principle of PureComponent

ShouldComponentUpdate () does not prevent unnecessary rendering of PureComponent components if their props or state are objects. So to use PureComponent features, follow these rules:

  • Make sure the data type is a value type
  • If it is a reference type, there should be no deep data changes (deconstruction).

React.memo

When using PureComponent, write the React component as a class, not as a function. After React V16.6.0, you can use React. Memo to implement functional components, as well as PureComponent functionality.

PureComponent of the List component:

const ListComponent = React.memo(() = > (
    <div>{this.props.data || 'loading'}</div>
))
Copy the code

Note: All of the above :point_right:The source code