React.Component与React.PureComponent

200 阅读3分钟

在React的使用中,由于ant design 组件库及公司内部cli及数据处理封装日趋成熟,使用起来颇为顺手,但是对于经验尚缺的前端,在项目中总会发现某一请求被执行多次或某一组件被渲染多次的情况,造成这个问题的原因是多样的:

  • 在错误的生命周期使用setState;
  • 父子组件使用React.Component时,没有在shouldComponentUpdate生命周期函数中进行判断,使得父组件所有的变化都会造成子组件的渲染;
  • 写动态子组件时,没有给定唯一的key;
  • .....

为了避免上述的问题,通常有以下几种解决方案:

  • 正确使用setState
  • 组件重新渲染时,会进入shouldComponentUpdate生命周期,此时进行必要的判断,可以避免一些不必要的渲染
  • 动态子组件的key 设置唯一的key,如果使用场景有限制,则至少应该设置其索引值作为key。
  • Immutable.js: Immutable数据类型减少数据判断的复杂性
  • React中的PureRenderMixin插件实现了shouldComponentUpdate中的浅比较。props 数据结构简单时,官方也推荐使用PureComponent,对于数据结构复杂的情况,官方文档中有推荐使用Immutable。

而本文所要讨论的一个知识点也由此展开,React.PureComponent是什么?和React.Component的区别是什么呢?

答案:React.PureComponent只是在shouldComponentUpdate中实现了state和props的浅比较。

以下通过简单的示例来说明。

// 父组件

import React, {Component, PureComponent} from 'react';
import Child from './child';

export default class Pure extends Component {
  constructor() {
    super();
    this.state = {
      arr: ['1'],
      obj: {
        name: "q"
      }
    };
    console.log('constructor');
  }

  changeState = () => {
    let { arr } = this.state;
    arr.push('2') 
    var obj = {
      name: "qu"
    }
    this.setState({
      // obj,
      // obj:{name:"Z"},
      arr // pureComponent下不会重新render
      // arr: [...arr, '2']
    })
  };

  render() {
    console.log('render');
    let { arr, obj } = this.state
    return (
      <div>
        <button onClick={this.changeState}>点击</button>
        <div>
          {arr.map((item) => {
            return item;
          })}
          {obj.name}
          <Child arr={arr}/>
        </div>
      </div>
    );
  }
}

大家可以自己来动手操作看下结果。简单总结如下:

组件继承自PureComponent时,如果state中数据是引用类型、直接改变该数据没有改变引用,则该组件不会重新渲染。

对于父子组件:

// 子组件

import React, { Component, PureComponent } from 'react';

export default class Child extends PureComponent {
  render() {
    console.log('example render');
    const { arr } = this.props;
    return(
      <div>
        {arr.map((item, key) => {
          return <p>{item}</p>
        })}
      </div>
    );
  }
}

父组件继承自PureComponent时,如果state中数据是引用类型且不改变其数据的引用时,则无论子组件继承自PureComponent或Component,子组件都不会重新渲染。

父组件继承自Component时,无论state中数据是何种类型,若子组件继承自PureComponent,子组件不会重新渲染;若子组件继承自Component,则state数据改变时子组件就会渲染。

总结:仅在state和props结构简单时才使用React.PureComponent,使用了React.PureComponent的组件的子组件,其props更新将不会重新渲染,所以使用时请保证其所有子组件均为“纯”组件。

注意:将 Render Props 与 React.PureComponent 一起使用时要小心。如果你在 render 方法里创建函数,那么使用 render prop 会抵消使用 React.PureComponent 带来的优势。因为浅比较 props 的时候总会得到 false,并且在这种情况下每一个 render 对于 render prop 将会生成一个新的值 - - -From React官方文档