React中PureComponent和Component的区别

2,820 阅读3分钟

在今天之前,一直都是处于边学习边用react开发项目的过程中,起初一直以为 PureComponent 和 Component 功能是一样的,只是 PureComponent 与 Component 相比提升了性能,但是为什么提升性能以及两者之间又有什么不同没有去进行深入的了解。近来在深入研究 React 的过程中,才发现了 PureComponent 是如何达到性能提升的优化,并对其进行了一番资料查找学习研究O(∩_∩)O~。

区别:

  • PureComponent 通过 propstate 的浅比较来实现 shouldComponentUpdate,当 prop 或 state 的值或者引用地址发生改变时,组件就会发生更新。

  • Component 只要 state 发生改变, 不论值是否与之前的相等,都会触发更新。

什么是浅比较?

就是对比当前状态(current)下一个状态(next)下的 prop 和 state时,比较基本数据类型是否相同(如: 'a' === 'a'), 而引用数据类型则是比较其引用地址是否相同,与值内容无关。

注意:在 PureComponent 中,当对传入的对象或者数组进行直接赋值时,因为并没有改变其引用地址,所以就不引起重新渲染。

示例一:

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

class ComponentDiff extends Component {
  render() {
    return (
      <div>
        different between PureComponent and Component <br />
        please open console
        <div style={{ display: 'flex' }}>
          <div style={{ marginRight: 200 }}>
            <ComponentDiffPure />
          </div>
          <ComponentDiffNormal />
        </div>
      </div>
    );
  }
}

export default ComponentDiff;

class ComponentDiffPure extends PureComponent {
  constructor() {
    super();
    this.state = { text: 'true' };
    console.log('pure-constructor');
  }

  changeState = () => {
    this.setState({ text: 'false' });
  };

  render() {
    console.log('pure-render');
    return (
      <div>
        pure
        <button onClick={this.changeState}>Click</button>
        <div>{this.state.text}</div>
      </div>
    );
  }
}

class ComponentDiffNormal extends Component {
  constructor() {
    super();
    this.state = { text: 'true' };
    console.log('normal-constructor');
  }

  changeState = () => {
    this.setState({ text: 'false' });
  };

  render() {
    console.log('normal-render');
    return (
      <div>
        normal
        <button onClick={this.changeState}>Click</button>
        <div>{this.state.text}</div>
      </div>
    );
  }
}

示例对应效果图如下,从操作中可以看出,在挂载时都会执行constructor和render方法,而在state改变时,PureComponent只在state的text值改变时执行了一次render方法,而Component会每次执行,这就是其浅对比功能体现的地方;

image.png

示例二:

这是一个组件的子树。每个节点中,SCU 代表 shouldComponentUpdate 返回的值,而 vDOMEq 代表返回的 React 元素是否相同。最后,圆圈的颜色代表了该组件是否需要被调停。

image.png

讲解: 节点 C2 的 shouldComponentUpdate 返回了 false,React 因而不会去渲染 C2,也因此 C4 和 C5 的 shouldComponentUpdate 不会被调用到。

对于 C1 和 C3,shouldComponentUpdate 返回了 true,所以 React 需要继续向下查询子节点。这里 C6 的 shouldComponentUpdate 返回了 true,同时由于渲染的元素与之前的不同使得 React 更新了该 DOM。

最后一个有趣的例子是 C8。React 需要渲染这个组件,但是由于其返回的 React 元素和之前渲染的相同,所以不需要更新 DOM。

显而易见,你看到 React 只改变了 C6 的 DOM。对于 C8,通过对比了渲染的 React 元素跳过了渲染。而对于 C2 的子节点和 C7,由于 shouldComponentUpdate 使得 render 并没有被调用。因此它们也不需要对比元素了。

总结

  1. PureComponent 不仅会影响本身,而且会影响子组件。
  2. 如果 prop 和 state 每次都会变,那么使用 Component 的效率会更好,因为浅比较也是需要时间的。
  3. 若有shouldComponentUpdate,则执行shouldComponentUpdate,若没有shouldComponentUpdate方法会判断是不是PureComponent,若是,进行浅比较

注意: 继承自Component的组件,若是shouldComponentUpdate返回false,就不会渲染了,继承自PureComponent的组件不用我们手动去判断prop和state,所以在PureComponent中使用shouldComponentUpdate会有如下警告: IndexPage has a method called shouldComponentUpdate(). shouldComponentUpdate should not be used when extending React.PureComponent. Please extend React.Component if shouldComponentUpdate is used.

参考资料:

react.docschina.org/docs/optimi…

blog.csdn.net/weixin_3624…

www.jianshu.com/p/b7733dc8f…