Your Guide to Efficient Re-rendering with React

简介: First, let’s understand the process of re-rendering in React. A React component translates raw data (consisting of props and state) into rich HTML.

Design_be_compact_to_be_elegant

First, let’s understand the process of re-rendering in React. A React component translates raw data (consisting of props and state) into rich HTML. You can control the state of the component by changing its props and state. The entire component is re-rendered whenever its props/state change.


Steps for re-rendering in React:


  1. When the props/state of a component change, React builds a new virtual DOM and compares the new and old virtual DOMs using the diff algorithm.
  2. If the new and old virtual DOM trees are not consistent, re-rendering begins.


1

The DOM operation is very time-consuming. To improve the performance of components, try to minimize unnecessary re-rendering of them.


Consider the following example.


The following figure shows a rendered component.


2

As the state of the component changes, the green node is re-rendered.

3

It is logical to think that only three nodes (highlighted in green) need to be updated to complete the component change.

4

However, as per React’s updating rules, whenever the props or state of a component change, the entire component is re-rendered. So, apart from the three green nodes, all other nodes (highlighted in yellow) are also re-rendered.


5

This is a huge waste of performance. For complex pages, this results in a very sub-standard user-experience. Therefore, to improve component performance, it is imperative to minimize unnecessary rendering.

Component Optimization Techniques


Due to the need for minimizing unnecessary rendering, let’s look at some techniques for component optimization.

Pure Component


A pure component in React is a component whose render function is dependent only on its props and state. With the same props and state, the rendered output receives the same results. The following code represents a pure component.

render() {
     return (
          {this.state.rows}   
     );
}

shouldComponentUpdate function


The function, shouldComponentUpdate, runs before rendering. Its return value determines whether the component is re-rendered.



  • Return value = True

    Whenever the component’s props/state change, the virtual DOM is re-constructed and compared using the diff algorithm. The comparison result decides whether the entire component should be re-rendered.


  • Return value = False

    The component is not re-rendered.


The default return value of the function is True, so re-rendering may occur. When re-rendering is not required, the default return value of the shouldComponentUpdate function is set to False.


The position of the shouldComponentUpdate function during component re-rendering is as shown in the following figure.

6

PureRenderMixin

React provides the official PureRenderMixin plugin, which makes the shouldComponentUpdate function return False. The plugin can reduce unnecessary re-rendering and improve performance to a certain extent. The use of the plugin is as follows:

 
import PureRenderMixin from 'react-addons-pure-render-mixin';
class FooComponent extends React.Component {
  constructor(props) {
    super(props);
    this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
  }

  render() {
    return <div className={this.props.className}>foo</div>;
  }
}

From the source code, you can see that the plugin is overwriting the shouldComponentUpdate function.

shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);}

This method makes a brief comparison between the current state and next state of a component. If the component’s state changes, a False result is returned. Otherwise, the True result is returned. This function can be further decomposed for implementation.

shouldComponentUpdate(nextProps, nextState) {
            return !shallowEqual(this.props, nextProps) ||
                                    !shallowEqual(this.state, nextState);
}

It compares the changes of props/state of the component. In the latest version of React, the basic class of React.PureComponent is provided, and the PureRenderMixin plugin is no longer needed.

Status Comparison

Let’s assume every component uses the PureRenderMixin plugin. Consider the following component.

shouldComponentUpdate(nextProps, nextState) {
            return !shallowEqual(this.props, nextProps) ||
                                    !shallowEqual(this.state, nextState);
}

To change the color of the component to blue, the following code is run.

shouldComponentUpdate(nextProps, nextState) {
            return !shallowEqual(this.props, nextProps) ||
                                    !shallowEqual(this.state, nextState);

}

The state comparison between two simple objects is depicted as:

7

If the two objects compared are complex, such as dates, functions, or objects with multiple nested layers, then the comparisons are either very time-consuming or unavailable.

You can overwrite the shouldComponentUpdate function to make it applicable to any item (including deep comparison/comparison of recursive layers). Deep comparison is time-consuming and hence not recommended. You should try to use simple props and state as well as avoid unnecessary attributes (or attributes calculated by other attributes in the state).

Immutable.js

The comparison of complex data is time-consuming or unavailable in React. But Immutable.js can solve this problem. It returns the same reference for immutable objects and returns a new reference for changed objects. The following code is used for comparison of the state.

shouldComponentUpdate() {
       return ref1 !== ref2;
}

Dynamic/Static Separation


Consider a component, such as a table.


<ScrollTable
width={300}

color='blue'

scrollTop={this.props.offsetTop}
/>

This is a scrollable table. The offsetTop represents the distance of visible area from the upper border of a browser. When the mouse scrolls, the value changes, altering the props of the component. Subsequently, the component is re-rendered.
Now, consider the following code.

<OuterScroll>
&lt;InnerTable width={300} color='blue'/&gt;
</OuterScroll>

The props of the InnerTable component is fixed. So, use of the pureRenderMixin plugin ensures the return value of shouldComponentUpdate as False. Irrespective of the state of OuterScroll and parent component, the InnerTable component is not to be re-rendered. In short, the sub-component isolates the state of the parent component.


By separating the changed and unchanged attributes, re-rendering is reduced, and performance improves. At the same time, the components can be easily separated and reused.

Child Components


In nested multi-layer and complex components, there are many sub-nodes. So, component updates take longer, making the component difficult to maintain. The unidirectional flow of information from parent component to child component may lead to loss of control over the components.

  • Children change over time

    Consider the following component, which is re-rendered every second (please note: this is a theoretical example only and not feasible in React).

class Parent extends Component {
  shouldComponentUpdate(nextProps) {
      return this.props.children != nextProps.children;
  }
  render() {
      return &lt;div&gt;{this.props.children}&lt;/div&gt;;
  }
}
setInterval(() => {
   ReactDOM.render(

      &lt;Parent&gt;

          &lt;div&gt;child&lt;/div&gt;

      &lt;/Parent&gt;

  );
}, 1000);

Children components that need to be re-rendered are recognized using the shouldComponentUpdate function by checking if the children and parent components are identical or not. Children is an attribute of props, so it is same all of the time. In theory, the component is not to be re-rendered. But in practice, it is re-rendered every time.


Let’s look at the structure of children in the following code.


8

Children are relatively complex objects and re-constructed during each component update. In other words, children are dynamically constructed, so the update is not equal every time. As a result, shouldComponentUpdate returns True every time, and the component is re-rendered. We can replace children with a variable in order for the same object to be constructed every time.

Independent children


Consider the following component.

 class TwoColumnSplit extends Component {
      shouldComponentUpdate() {
          return false;
      }
      render() {
          return (
       <div>
                <FloatLeft>{this.props.children[0]}</FloatLeft>
                <FloatRight>{this.props.children[1]}</FloatRight>
            </div>
          );
      }
  } <TwoColumnSplit>
      <TargetContainer/>
      <BudgetContainer/>
   </TwoColumnSplit>

The shouldComponentUpdate function returns False, and the component doesn’t change with outside state changes. This is because the components TargetContainer and BudgetContainer did not get any information from their parent element, and the children and the parent component are isolated. In fact, TwoColumnSplit plays the role of isolation. For components that do not need to get data from the outside, you can isolate them from external changes by returning a False value to reduce re-rendering.

Container and Component


You can also isolate external changes by using component containers. A container is a data layer, with the component responsible for rendering corresponding components based on data obtained, without any data interaction. The following shows a container and its components.

class BudgetContainer extends Component {
  constructor(props) {
      super(props);
      this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
  }
  computeState() {
      return BudgetStore.getStore()
  }
  render() {
return <Budget {...this.state}/>
   }
}

Containers should not have props and children, so a container and its parent component are isolated. Therefore, no re-rendering is needed due to external factors.


To move the position of a component, you only have to put the component in the right position. You can move it to any place, as well as use in different applications and tests. You should consider the source of internal data to write different containers in different environments.

Conclusion


We covered the importance of re-rendering efficiently in React. Also, you learned various techniques for component optimization, including shouldComponentUpdate and PureRenderMixin functions, status comparison, Immutable.js, dynamic/static separation, child components, and containers.

目录
相关文章
|
2月前
|
存储 程序员 编译器
Modern C++
Modern C++
|
6月前
|
开发框架 容器
SAP UI5 Flexible Programming Model Explorer
SAP UI5 Flexible Programming Model Explorer
39 0
|
Web App开发 JavaScript 前端开发
Modern模式引发qiankun的一场“命案”
前沿:文章的起源在于开发环境中使用qiankun框架,父应用加载子应用遇到一则报错 Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec 直接的翻译意思就是加载模块脚本失败:服务器以非JavaScript MIME类型“text/html”去响应。而也是这个问题引发了我的思考,到底是什么问题导致?
859 0
Modern模式引发qiankun的一场“命案”
《The Great Gatsby》Day 22
《The Great Gatsby》Day 22 2.大概内容 一度是灯火通明的Gatsby家,在一个夏夜突然暗淡下来,那些怀着希望而来的人们,看到这副景象也都失望地离开了。。。Nick开始以为Gatsby生病了或是去了外地,后来才
80 0
|
前端开发
《the Great Gatsby》Day 26
Gatsby告诉Daisy,她只要说自己从未爱过Tom,便能就此解脱,幸福地和自己在一起;但是当Tom说出曾经的种种,回忆淹没了Daisy,她没办法违背自己的内心——她曾深爱过Tom。Daisy说自己还是会离开Tom,Tom情急之下说出了Gatsby光鲜外表背后的那些不光彩的勾当。Daisy再一次恳求Tom带她回家,Tom却让Gatsby开车送她
86 0
《The Great Gatsby》Day 20
让Nick感到惊讶的是Tom Mr.Sloane和一个穿着马术服装的女子骑着马来到了Gatsby家,女子还邀请Gatsby和Nick去她家共进晚餐。Tom不放心Daisy自己一个人到处走动,便陪着她来到了Gatsby的一个聚会,聚会上Tom又是一如既往地到处调情,但这也同时给Daisy和Gatsby单独相处的机会
91 0
《The Great Gatsby》Day 19
Daisy沉醉于Gatsby家的繁华和精致,又因这5年逝去的时光而黯然神伤;Gatsby望着Daisy,欣喜又惶恐,前不久他还只能凝望海湾对面的Daisy家的那道绿光,期盼能与她充分,现在Daisy却离自己那么近,一切幸福显得有点不真实。
125 0
《The Great Gatsby》Day 21
在Gatsby的又一次party上,Daisy和Tom也应邀前来参加,一位又一位女客涂脂抹粉,男女狂欢的热闹繁华夜场生活反射出当时赤裸裸的美国梦。Gatsby因Tom去勾搭其
145 0
《The Great Gatsby》Day 12
舞会快结束的时候,Jordan和Gatsby也从书房出来了,Jordan告诉Nick她刚刚听到了最不可思议的事,但是又故意卖关子不肯说说是什么;她被伙伴们簇拥着上了车,和Nick告别时叮嘱Nick一定要给她打电话,Nick和Gatsby道别后也回家了。生活一天天过去,Nick也渐渐爱上了纽约。
71 0
《The Great Gatsby》Day 15
Gatsby向Nick介绍了他的朋友Mr.Wolfsheim,Mr.Wolfsheim和Nick聊了一会就走了,Gatsby告诉Nick他就是当年操纵棒球联赛“黑袜联赛”的人。Nick发现Tom也在餐厅,带Gatsby过去打招呼,但是Gatsby看见
96 0