Skip to content

React 的 PureComponent Vs Component ​

本节目标:理解“React 的 PureComponent Vs Component”的核心思路,并能把它用于实际开发或面试表达。

一.它们几乎完全相同,但是PureComponent通过prop和state的浅比较来实现shouldComponentUpdate,某些情况下可以用PureComponent提升性能
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==组件,设置了一个==state==是==isShow==,通过一个按钮点击可以改变它的值,结果是:初始化的时候输出的是==constructor==,==render==,而第一次点击按钮,会输出一次render,即重新渲染了一次,界面也会从显示==false==变成显示==true==,但是当这个组件是继承自==PureComponent==的时候,再点击的时,不会再输出==render==,即不会再重新渲染了,而当这个组件是继承自==Component==时,还是会输出==render==,还是会重新渲染,这时候就是==PureComponent==内部做了优化的体现
4.同理也适用于==string==,==number==等基本数据类型,因为基本数据类型,值改变了就算改变了
==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==时,初始化依旧是输出==constructor==和==render==,但是当点击按钮时,界面上没有变化,也没有输出==render==,证明没有渲染,但是我们可以从下面的注释中看到,每点击一次按钮,我们想要修改的==arr==的值已经改变,而这个值将去修改==this.state.arr==,但是因为在==PureComponent==中==浅比较==这个数组的引用没有变化所以没有渲染,==this.state.arr==也没有更新,因为在==this.setState()==以后,值是在==render==的时候更新的,这里涉及到==this.setState()==的知识
6.但是当这个组件是继承自==Component==的时候,初始化依旧是输出==constructor==和==render==,但是当点击按钮时,界面上出现了变化,即我们打印处理的==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==的引用发生了变化,所以初始化的时候输出==constructor==和==render==后,每次点击按钮都会输出==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==时:下面的结果初始化时输出为==constructor==,==IndexPage render==,==example render==,但是当我们点击按钮时,界面没有变化,因为这个==this.state.person==对象的引用没有改变,只是改变了它里面的属性值所以尽管子组件是继承==Component==的也没有办法渲染,因为父组件是==PureComponent==,父组件根本没有渲染,所以子组件也不会渲染
3.父组件继承==PureComponent==,子组件继承==PureComponent==时:因为渲染在父组件的时候就没有进行,相当于被拦截了,所以子组件是==PureComponent==还是==Component==根本不会影响结果,界面依旧没有变化
4.父组件继承==Component==,子组件继承==PureComponent==时:结果和我们预期的一样,即初始化是会输出==constructor==,==IndexPage render==,==example render==,但是点击的时候只会出现==IndexPage render==,因为父组件是==Component==,所以父组件会渲染,但是
当父组件把值传给子组件的时候,因为子组件是==PureComponent==,所以它会对==prop==进行浅比较,发现这个==person==对象的引用没有发生变化,所以不会重新渲染,而界面显示是由子组件显示的,所以界面也不会变化
5.父组件继承==Component==,子组件继承==Component==时:初始化是会输出==constructor==,==IndexPage render==,==example render==,当我们第一次点击按钮以后,界面发生变化,后面就不再改变,因为我们一直把它设置为sxt2,但是每点击一次都会输出==IndexPage render==,==example render==,因为每次不管父组件还是子组件都会渲染
6.所以正如下面第四条说的,如果==state==和==prop==一直变化的话,还是建议使用==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==的组件不用我们手动去判断==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.
也是比较好理解的,就是不要在==PureComponent==中使用==shouldComponentUpdate==,因为根本没有必要

> 来自

 <https://www.jianshu.com/p/c41bbbc20e65>

本站总访问 — 次