React high-level component application (1) Improve the rendering efficiency of antd Table components

I. Introduction

For react high-end components. Everyone basically only knows the definition and usage. In actual development, it may not be used much. Team down a job, rewrite some of Antd Tablerendering as the main function of the module, we found some problems here, Antd Tablewhen rendering, even if there is no change Tablein props, just change the package Tablecomponents, Tablethe components will be re-rendered.

2. The problem arises

import {
    
     Table} from 'antd';
class TestRoot extends Component {
    
    
	change() {
    
    
	 		this.setState({
    
    
	            self_state: 2
	        });
	}
	render() {
    
    
	        const columns = [
	            {
    
    
	                title: '姓名',
	                dataIndex: 'name',
	                key: 'name',
	                render: (text, record, index) => {
    
    
	                    console.log('rerendered !!!')
	                    return <div>{
    
    text}</div>;
	                }
	            },
	            {
    
    
	                title: '年龄',
	                dataIndex: 'age',
	                key: 'age'
	            },
	            {
    
    
	                title: '住址',
	                dataIndex: 'address',
	                key: 'address'
	            }
	        ];
	        return (
	            <div>
	                <h1>{
    
    this.state.self_state}</h1>
	                <Table columns={
    
    columns} dataSource={
    
    this.state.data_arr} />
	            </div>
	        );
	    }
 }

When the TestRootstate of my component changes, I will find that the console keeps outputting rerendered !!!such prompts. Prove that Tablethe re-rendering operation is done inside the form.

Three, analysis & solution

For AntdUI libraries like this, the problem of repeated rendering is an optimization problem. Generally speaking, the library does not overdo these optimizations. What we have to do is to filter non-essential state rendering by controlling the Tablecomponent shouldComponentUpdate. At this time, we thought of using high-level component encapsulation, using reverse inheritance, and injecting it into the Tablecomponent's rendering logic:

import {
    
     Table } from 'antd';
const withPure = (Comp) => {
    
    
    return class PureTable extends Comp {
    
    
        shouldComponentUpdate(nextProps, nextState) {
    
    
            //--在这里控制
            return true;
        }
        render() {
    
    
            return super.render();
        }
    };
};
export default withPure(Table)

How to use, replace the original direct use Tablewith use PureTable.

 return (
          <div>
               <h1>{
    
    this.state.self_state}</h1>
               <PureTable columns={
    
    columns} dataSource={
    
    this.state.data_arr} />
           </div>
       );

Please note that this is the second way to implement high-end components. It adopts the form of inheriting the source component, so that we can control the rendering process by overwriting some methods of the source component, which is a deep attack injection.

1. The first level of shallow comparison through shallowCompare

Regarding shallowComparethe usage, you can Baidu by yourself, which is a simple comparison. The changes in the first layer of state and props can be judged. But it is impossible to judge the deep reference object.

npm i react-addons-shallow-compare --save

import {
    
     Table } from 'antd';
let shallowCompare = require('react-addons-shallow-compare');
const withPure = (Comp) => {
    
    
    return class PureTable extends Comp {
    
    
        shouldComponentUpdate(nextProps, nextState) {
    
    
           return !shallowCompare(this, nextProps, nextState);
        }
        render() {
    
    
            return super.render();
        }
    };
};
export default withPure(Table)

2. In-depth comparison through lodash _.isEqual

After testing the above code, it is found that after changing self_state, the table does not render again. But it is obvious that when my dataSource changes, shallowCompare will not judge it and prohibits the rendering of the table. For example, the following example of directly modifying dataSource:

change3() {
    
    
    const {
    
     data_arr } = this.state;

        data_arr[0].name = '胡二狗';

        this.setState({
    
    
            data_arr
        });
}

There are two branches here. The first one is to judge the deep props and state of the required Table based on the business situation, such as the dataSource attribute, or directly use the deep comparison to judge the state and props. The second method is obviously less efficient, but it can ensure that the rendering of the table will not be affected.


import {
    
     Table } from 'antd';
let shallowCompare = require('react-addons-shallow-compare');
const withPure = (Comp) => {
    
    
    return class PureTable extends Comp {
    
    
        shouldComponentUpdate(nextProps, nextState) {
    
    
           const is_sample = shallowCompare(this, nextProps, nextState);

           if(!is_sample) {
    
    return true;}

           const state_sample = _.isEqual(nextState, this.state);
           if(!state_sample) {
    
    return true;}

           
           const props_sample = _.isEqual(nextProps, this.props);
           if(!props_sample) {
    
    return true;}
           
           return false;
        }
        render() {
    
    
            return super.render();
        }
    };
};
export default withPure(Table)

Up to this point, in theory, when I only change the state of the Root component, the rendering of the table will not be triggered. However, when lodash performs a deep comparison, there is still an inconsistent attribute judgment. After deep debugging, it is found that the render function in the columns attribute passed by the two props is different. A problem with the writing of the table was found here.

 const columns = [
         {
    
    
               title: '姓名',
               dataIndex: 'name',
               key: 'name',
               render: (text, record, index) => {
    
    
                   console.log('rerendered !!!')
                   return <div>{
    
    text}</div>;
               }
           },
           {
    
    
               title: '年龄',
               dataIndex: 'age',
               key: 'age'
           },
           {
    
    
               title: '住址',
               dataIndex: 'address',
               key: 'address'
           }
       ];
       return (
           <div>
                <h1>{
    
    this.state.self_state}</h1>
                <Table columns={
    
    columns} dataSource={
    
    this.state.data_arr} />
            </div>
        );

Everyone pay attention to the renderfunction in the name column . This way of writing will cause a new renderfunction reference to be created every time, which leads to inconsistent judgments when lodash compares deeply and causes the table to re-render.

Define the render method in the class and modify the definition as follows:

//--省略
    render_column_name = (text, record, index) => {
    
    
        console.log('column rendered!');
        return <TestColumnChild name={
    
    text} ></TestColumnChild>;
    }
    render() {
    
    
        const columns = [
            {
    
    
                title: '姓名',
                dataIndex: 'name',
                key: 'name',
                render: this.render_column_name
            },
            {
    
    
                title: '年龄',
                dataIndex: 'age',
                key: 'age'
            },
            {
    
    
                title: '住址',
                dataIndex: 'address',
                key: 'address'
            }
        ];
   )

After testing, everything is normal. Setting the state of Root itself will no longer cause the table to re-render.

Four, sublimation

In fact, we found that we just implemented one ourselves through the wrapper pureComponent. This wrapper can actually wrap any component, not just Table, if it follows the general writing of the above-mentioned depth comparison. In fact, this is the essence of high-end components. Here we introduce a library, recomposewhich is lodash in react. Here is just an introduction and a recompose realization of my above writing. The following chapters will share more details on recompose.

import {
    
     compose, pure } from 'recompose';
import {
    
     Table} from 'antd';

const composeHoc = compose(pure);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
export default  composeHoc(Table);

Is not it simple?

The implementation here is to package components through the recompose native pure wrapper. It's just that pure here is a shallow comparison. Recompose provides a large number of short and beautiful wrappers, which can be packaged layer by layer through compose to enhance our components.

Guess you like

Origin blog.csdn.net/qq_29722281/article/details/107518148