Performance optimization in React through Pure Render and Immutable

Brief introduction: render in React has unnecessary rendering, which can be reduced by Puer Render (Pure Component), but Puer Render is only a shallow comparison, and can not achieve performance optimization on deep objects. Pure Render combined with Immutable can reduce rendering times.

1. render in React

Unnecessary rendering exists only through render in React, which can be divided into two categories.

(1) There is no change in its own state

In React render, whenever a setState behavior occurs, it will be rendered again, even if the properties of setState have not changed before or after, such as:

class TestComponent extends React.Component{
  constructor(props){
    super(props);
    this.state={
      count:0
    }
  }
  componentDidMount(){
    let self=this;
    setTimeout(function(){
      self.setState({
        count:0
      })
    },1000)
  }
  componentDidUpdate(){
    console.log('Component updates');
  }
  render(){
    return <div>1</div>
  }
}

In this component, the value of our setState hasn't changed before or after, but calling this component will output:

// Component updates

This means that as long as setState occurs, the component will render again even if the value does not change before and after.

(2) Pros passed by parent components cause render of all child components

The value in the parent component is passed to the child component, and render is rendered again even if some of the child components do not need to be re-rendered. For example, the parent component is Father:

class Father extends React.Component{
  constructor(props){
    super(props);
    this.state={
      obj:{
        title:'test immutable',
        childZero:{
          name:'childZero',
          age:0
        },
        childOne:{
          name:'childOne',
          age:1
        },
        childTwo:{
          name:'childTwo',
          age:2
        }
      }
    }
  }
  componentDidMount(){
    let self=this;
    let {obj}=this.state;
    // setTimeout(function(){
    //   self.setState(( {obj}) => ( {
    //      obj: obj.update( 'childZero', (v)=>v+v)
    //   }) );
    // },1000);
    setTimeout(function(){
      self.setState({
        obj:obj
      })
    },1000)
  }
  render(){
    const {obj}=this.state;
    return <div>
             <ChildZero obj={obj}/>
             <ChildOne obj={obj}/>
             <ChildTwo obj={obj}/>
           </div>
  }
}

The parent component has three subcomponents:

class ChildZero extends React.Component{
  constructor(props){
    super(props);
  }
  componentDidUpdate(){
    console.log('childTwo Triggered the update')
  }
  render(){
    return <div>3</div>
  }
}
class ChildOne extends React.Component{
  constructor(props){
    super(props);
  }
  componentDidUpdate(){
    console.log('childTwo Triggered the update')
  }
  render(){
    return <div>3</div>
  }
}
class ChildTwo extends React.Component{
  constructor(props){
    super(props);
  }
  componentDidUpdate(){
    console.log('childTwo Triggered the update')
  }
  render(){
    return <div>3</div>
  }
}

In the componentDidMout method of the parent component, setState then observes the update of the child component and finds that all the child components will be updated. The output is as follows:

// childZero triggered the update
 // childOne triggered the update
 // childTwo triggered the update

2. Pure Render reduces unnecessary updates on shallow objects

By defining components as Pure Render, unnecessary updates can be reduced through shallow comparisons. We use PureComponent. Similarly, we take 1 (1) as an example:

class TestComponent extends React.PureComponent{
  constructor(props){
    super(props);
    this.state={
      count:0
    }
  }
  componentDidMount(){
    let self=this;
    setTimeout(function(){
      self.setState({
        count:0
      })
    },1000)
  }
  componentDidUpdate(){
    console.log('Component updates');
  }
  render(){
    return <div>1</div>
  }
}

Component is replaced by PureComponent. If only shallow object attributes are present, there will be no unnecessary rendering when the attributes before and after setState remain unchanged. But for deep objects, pure Render cannot be implemented.

3. Implementing performance optimization of deep object through Immutable

Immutable implements the immutable data structure in js. immutable has the characteristics of immutability and persistence. Through data sharing, the process of modifying the corresponding attributes to achieve deep cloning will only affect the parent attributes.

Through immutable js, it is convenient to judge the "equality" of deep objects. In the performance optimization of React, the life cycle function shouldComponetUpdate is used to judge whether it needs to be updated, and the deep comparison between props and state s is made.

shouldComponentUpdate(nextProps,nextState){
    //Deep judgment using immutable
    const thisProps=this.props;
    if(Object.keys(thisProps).length!==Object.keys(nextProps).length){
      return true;
    }

    for(const key in nextProps){
      console.log(is(thisProps[key],nextProps[key]));
      if(!is(thisProps[key],nextProps[key])){
        return true;
      }
    }
    return false;
  }

If true is returned, render is performed, and if false is returned, render is not done, thus controlling whether deep objects need to be rendered again to optimize performance.

The immutable is used here mainly because it has the following characteristics:

I) Faster, faster than deep-level cloning if the objects (Map s) or arrays (List s) are the same.

II) Security refers to the addition and deletion of all immutable checks, are incremental, will not make the original data lost.

3. Disadvantages of immutable

There are also some drawbacks in using immutalbe:

(1) immutable JS source files are large

(2) It is very intrusive.

Keywords: React

Added by SuprSpy79 on Tue, 14 May 2019 16:50:13 +0300