PureComponent和Component

在react使用中相信大家一定碰到或者使用過Component和PureComponent,但是這兩者具體有什么區(qū)別,實(shí)現(xiàn)這種區(qū)別的原理是什么?(拼多多一面的時(shí)候被問了這個(gè)問題......)

區(qū)別

PureComponent通過prop和state的淺比較來實(shí)現(xiàn)shouldComponentUpdate,某些情況下可以用PureComponent提升性能

所以其實(shí)就是PureComponent在內(nèi)部寫好了shouldComponentUpdate這個(gè)函數(shù),具體的寫法如下:

    if (this._compositeType === CompositeTypes.PureClass) {
        shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState);
    }
    // 所做的事情就是對props和state與之前的值進(jìn)行一次淺比較,如果淺比較發(fā)現(xiàn)前后都沒有變化,那么就不觸發(fā)update,否則觸發(fā)update

相比于PureComponent組件,Component組件的shouldComponentUpdate是默認(rèn)返回true的,也就是說每一次setState,無論這次setState是否真的改變了狀態(tài)都會(huì)觸發(fā)update,或者只要父組件重新render了,傳下來的props即使不發(fā)生變化(甚至沒有傳props進(jìn)子組件)那子組件也會(huì)重新update一次,這在很多情況下顯然是多余的更新,所以說PureComponent在一些情況下可以提升性能,但是使用時(shí)也有一些注意點(diǎn),不然容易產(chǎn)生bug

來看一下Component組件的任性render:

    class Child extends React.Component {
        constructor(props) {
            super(props);
        }

        render() {
            console.log('child render')
            return <div>hahahah</div>
        }
    }

    class IndexPage extends React.Component{
        constructor() {
            super();
            this.state = {
                arr: [1]
            };
            console.log('constructor');
        }
        changeState = () => {
            const { arr } = this.state;
            arr.push('@')
            // 這里實(shí)際上arr的指向并沒有發(fā)生變化,但是setState之后還是會(huì)觸發(fā)update,因?yàn)镮ndexPage是繼承自Component組件的,只要setState就會(huì)update,(如果現(xiàn)在改成繼承自PureComponent,那么在shouldComponentUpdate里面的判斷就會(huì)返回false,那么就不會(huì)觸發(fā)update,那么子組件也不會(huì)update了)
            this.setState({
                arr
            })
        };
        render() {
            console.log('render');
            return (
                <div>
                    <button onClick={this.changeState}>點(diǎn)擊</button>
                    <div>{this.state.arr.toString()}</div>
                    // 我們可以發(fā)現(xiàn),點(diǎn)擊按鈕之后展示的內(nèi)容一致在發(fā)生變化
                    <Child />
                    // 父組件沒有傳入props進(jìn)入Child組件,但是只要父組件重新render了,因?yàn)樽咏M件是繼承自Component的,所以默認(rèn)shouldComponentUpdate返回true,所以也會(huì)無腦render,即使和原來一模一樣,(如果把子組件改成繼承自PureComponent,那么即使父組件update,子組件也不會(huì)update,因?yàn)椴]有傳入props到子組件,在子組件的shouldComponentUpdate里面的判斷會(huì)返回false)
                </div>
            );
        }
    }

注意點(diǎn)

所以在使用PureComponent時(shí)需要有些注意點(diǎn):

  1. 在state里面使用復(fù)雜類型的時(shí)候,如數(shù)組,避免直接對數(shù)組進(jìn)行操作而忘記改變指向,這時(shí)即使數(shù)組實(shí)際內(nèi)容發(fā)生了變化也不會(huì)update,像上面例子里面那樣對數(shù)組的操作

         const { arr } = this.state;
         arr.push('@');
         this.setState({
             arr
         })
         // 這種做法只會(huì)觸發(fā)Component的update而不會(huì)觸發(fā)PureComponent的update,實(shí)際上,不管在哪找寫法里面都不推薦直接對state里面的內(nèi)容進(jìn)行操作,正確的做法應(yīng)該是下面這樣
         const { arr } = this.state;
         const newArr = [...arr];
         newArr.push('@');
         this.setState({
             arr: newArr
         })
    
    
  2. 對于基本數(shù)據(jù)類型來說,值發(fā)生變化PureComponent就會(huì)update,對于復(fù)雜數(shù)據(jù)類型要指向發(fā)生變化

    class Example extends React.PureComponent {
        constructor(props) {
            super(props);
            this.state = {
                isShow: false,
            }
        }

        handleClick = () => {
            this.setState({
                isShow: true
            })
        }

        render() {
            console.log('render');
            // 第一次組件初始化render的時(shí)候會(huì)打印一次render
            // 第一次點(diǎn)擊按鈕觸發(fā)事件會(huì)觸發(fā)一次render
            // 后續(xù)再點(diǎn)擊按鈕就不會(huì)觸發(fā)render了,因?yàn)楹罄m(xù)的isShow的值始終是true,setState也沒有發(fā)生變化
            // 如果把組件改成繼承自Component的話,那么所有的點(diǎn)擊都會(huì)觸發(fā)render
            return ....
        }

    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容