React 的 PureComponent Vs Component

栏目: 服务器 · 发布时间: 6年前

内容简介:1.所谓而本来我们做的事情如下,这里判断了2.上面提到的某些情况下可以使用

1.所谓 浅比较 (shallowEqual),即react源码中的一个函数,然后根据下面的方法进行是不是 PureComponent 的判断,帮我们做了本来应该我们在 shouldComponentUpdate 中做的事情

if (this._compositeType === CompositeTypes.PureClass) {
  shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState);
}
复制代码

而本来我们做的事情如下,这里判断了 state 有没有发生变化(prop同理),从而决定要不要重新渲染,这里的函数在一个继承了 Component 的组件中,而这里 this.state.person 是一个对象,你会发现, 在这个对象的引用没有发生变化的时候是不会重新 render 的(即下面提到的第三点),所以我们可以用 shouldComponentUpdate 进行优化,这个方法如果返回 false ,表示不需要重新进行渲染,返回 true 则重新渲染,默认返回 true

shouldComponentUpdate(nextProps, nextState) {
    return (nextState.person !== this.state.person);
  }
复制代码

2.上面提到的某些情况下可以使用 PureComponent 来提升性能,那具体是哪些情况可以,哪些情况不可以呢,实践出真知

3.如下显示的是一个 IndexPage 组件,设置了一个 stateisShow ,通过一个按钮点击可以改变它的值,结果是:初始化的时候输出的是 constructorrender , 而第一次点击按钮,会输出一次render,即重新渲染了一次,界面也会从显示 false 变成显示 true ,但是当这个组件是继承自 PureComponent 的时候,再点击的时,不会再输出 render ,即不会再重新渲染了, 而当这个组件是继承自 Component 时,还是会输出 render ,还是会重新渲染,这时候就是 PureComponent 内部做了优化的体现

4.同理也适用于 stringnumber 等基本数据类型,因为基本数据类型,值改变了就算改变了

import React, { PureComponent } from 'react';

class IndexPage extends PureComponent{
  constructor() {
    super();
    this.state = {
      isShow: false
    };
    console.log('constructor');
  }
  changeState = () => {
    this.setState({
      isShow: true
    })
  };
  render() {
    console.log('render');
    return (
      <div>
        <button onClick={this.changeState}>点击</button>
        <div>{this.state.isShow.toString()}</div>
      </div>
    );
  }
}
复制代码

5.当这个 this.state.arr 是一个数组时,且这个组件是继承自 PureComponent 时,初始化依旧是输出 constructorrender ,但是当点击按钮时,界面上没有变化,也没有输出 render ,证明没有渲染,但是我们可以从下面的注释中看到,每点击 一次按钮,我们想要修改的 arr 的值已经改变,而这个值将去修改 this.state.arr ,但是因为在 PureComponent浅比较 这个数组的引用没有变化所以没有渲染, this.state.arr 也没有更新,因为在 this.setState() 以后,值是在 render 的时候更新的, 这里涉及到 this.setState() 的知识

6.但是当这个组件是继承自 Component 的时候,初始化依旧是输出 constructorrender ,但是当点击按钮时,界面上出现了变化,即我们打印处理的 arr 的值输出,而且每点击一次按钮都会输出一次 render ,证明已经重新渲染, this.state.arr 的值已经更新,所以 我们能在界面上看到这个变化

import React, { PureComponent } from 'react';

class IndexPage extends PureComponent{
  constructor() {
    super();
    this.state = {
      arr:['1']
    };
    console.log('constructor');
  }
  changeState = () => {
    let { arr } = this.state;
    arr.push('2');
    console.log(arr);
    // ["1", "2"]
    // ["1", "2", "2"]
    // ["1", "2", "2", "2"] 
    // ....
    this.setState({
      arr
    })
  };
  render() {
    console.log('render');
    return (
      <div>
        <button onClick={this.changeState}>点击</button>
        <div>
          {this.state.arr.map((item) => {
            return item;
          })}
        </div>
      </div>
    );
  }
}

复制代码

7.下面的例子用 扩展运算符 产生新数组,使 this.state.arr 的引用发生了变化,所以初始化的时候输出 constructorrender 后,每次点击按钮都会输出 render ,界面也会变化,不管该组件是继承自 Component 还是 PureComponent

import React, { PureComponent } from 'react';

class IndexPage extends PureComponent{
  constructor() {
    super();
    this.state = {
      arr:['1']
    };
    console.log('constructor');
  }
  changeState = () => {
    let { arr } = this.state;
    this.setState({
      arr: [...arr, '2']
    })
  };
  render() {
    console.log('render');
    return (
      <div>
        <button onClick={this.changeState}>点击</button>
        <div>
          {this.state.arr.map((item) => {
            return item;
          })}
          </div>
      </div>
    );
  }
}
复制代码

8.上面的情况同样适用于 对象 的情况

二.PureComponent不仅会影响本身,而且会影响子组件,所以PureComponent最佳情况是展示组件

1.我们让 IndexPage 组件里面包含一个子组件 Example 来展示 PureComponent 是如何影响子组件的

2.父组件继承 PureComponent ,子组件继承 Component 时:下面的结果初始化时输出为 constructorIndexPage renderexample render ,但是当我们点击按钮时,界面没有变化,因为这个 this.state.person 对象的引用没有改变,只是改变了它里面的属性值 所以尽管子组件是继承 Component 的也没有办法渲染,因为父组件是 PureComponent ,父组件根本没有渲染,所以子组件也不会渲染

3.父组件继承 PureComponent ,子组件继承 PureComponent 时:因为渲染在父组件的时候就没有进行,相当于被拦截了,所以子组件是 PureComponent 还是 Component 根本不会影响结果,界面依旧没有变化

4.父组件继承 Component ,子组件继承 PureComponent 时:结果和我们预期的一样,即初始化是会输出 constructorIndexPage renderexample render ,但是点击的时候只会出现 IndexPage render ,因为父组件是 Component ,所以父组件会渲染,但是 当父组件把值传给子组件的时候,因为子组件是 PureComponent ,所以它会对 prop 进行浅比较,发现这个 person 对象的引用没有发生变化,所以不会重新渲染,而界面显示是由子组件显示的,所以界面也不会变化

5.父组件继承 Component ,子组件继承 Component 时:初始化是会输出 constructorIndexPage renderexample render ,当我们第一次点击按钮以后,界面发生变化,后面就不再改变,因为我们一直把它设置为sxt2,但是每点击一次 都会输出 IndexPage renderexample render ,因为 每次不管父组件还是子组件都会渲染

6.所以正如下面第四条说的,如果 stateprop 一直变化的话,还是建议使用 Component ,并且 PureComponent 的最好作为展示组件

//父组件
import React, { PureComponent, Component } from 'react';
import Example from "../components/Example";

class IndexPage extends PureComponent{
  constructor() {
    super();
    this.state = {
      person: {
        name: 'sxt'
      }
    };
    console.log('constructor');
  }
  changeState = () => {
    let { person } = this.state;
    person.name = 'sxt2';
    this.setState({
      person
    })
  };
  render() {
    console.log('IndexPage render');
    const { person } = this.state;
    return (
      <div>
        <button onClick={this.changeState}>点击</button>
        <Example person={person} />
      </div>
    );
  }
}
//子组件
import React, { Component } from 'react';

class Example extends Component {

  render() {
    console.log('example render');
    const { person } = this.props;
    return(
      <div>
        {person.name}
      </div>
    );
  }
}
复制代码

三.若是数组和对象等引用类型,则要引用不同,才会渲染

四.如果prop和state每次都会变,那么PureComponent的效率还不如Component,因为你知道的,进行浅比较也是需要时间

五.若有shouldComponentUpdate,则执行它,若没有这个方法会判断是不是PureComponent,若是,进行浅比较

1.继承自 Component 的组件,若是 shouldComponentUpdate 返回 false ,就不会渲染了,继承自 PureComponent 的组件不用我们手动去判断 propstate ,所以在 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.

也是比较好理解的,就是不要在 PureComponent 中使用 shouldComponentUpdate ,因为根本没有必要


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Android 源码设计模式解析与实战

Android 源码设计模式解析与实战

何红辉、关爱民 / 人民邮电出版社 / 2015-11 / 79.00元

本书专门介绍Android源代码的设计模式,共26章,主要讲解面向对象的六大原则、主流的设计模式以及MVC和MVP模式。主要内容为:优化代码的首步、开闭原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特原则、单例模式、Builder模式、原型模式、工厂方法模式、抽象工厂模式、策略模式、状态模式、责任链模式、解释器模式、命令模式、观察者模式、备忘录模式、迭代器模式、模板方法模式、访问者模式、中介......一起来看看 《Android 源码设计模式解析与实战》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具