1. 程式人生 > >React.Component 與 React.PureComponent(React之性能優化)

React.Component 與 React.PureComponent(React之性能優化)

rec class關鍵字 sets ase update 截圖 開發 報錯 join

前言

先說說 shouldComponentUpdate

提起React.PureComponent,我們還要從一個生命周期函數 shouldComponentUpdate 說起,從函數名字我們就能看出來,這個函數是用來控制組件是否應該被更新的。

React.PureComponent 通過prop和state的淺對比來實現shouldComponentUpate()。

簡單來說,這個生命周期函數返回一個布爾值。

如果返回true,那麽當props或state改變的時候進行更新;

如果返回false,當props或state改變的時候不更新,默認返回true。

(這裏的更新不更新,其實說的是執不執行render函數,如果不執行render函數,那自然該組件和其子組件都不會重新渲染啦)

重寫shouldComponentUpdate可以提升性能,它是在重新渲染過程開始前觸發的。當你明確知道組件不需要更新的時候,在該生命周期內返回false就行啦!

下面是一個重寫shouldComponentUpdate的例子:

class CounterButton extends React.Component {
    state={
        count: 1
    }
    shouldComponentUpdate(nextProps, nextState) {
        const {color}=this.props;
        const {count}=this.state;
        if (color !== nextProps.color) {
            return true;
        }
        // 重寫shouldComponentUpdate若將此處count相關邏輯註釋則count變化頁面不渲染
        // if (count !== nextState.count) {
        //     return true;
        // }
        return false;
    }

    render() {
        const {color}=this.props;
        const {count}=this.state;
        return (
             <button 
                style={{color}}
                onClick={() => this.setState(state => ({count: state.count + 1}))}
            >
                Count: {count}
            </button>
        );
    }
}

React.Component 與 React.PureComponent
言歸正傳,接下來說我們今天要討論的React.Component 與 React.PureComponent。

通常情況下,我們會使用ES6的class關鍵字來創建React組件:

class MyComponent extends React.Component {
    // some codes here ...
}

但是,你也可以創建一個繼承React.PureComponent的React組件,就像這樣

class MyComponent extends React.PureComponent {
    // some codes here
}

那麽,問題來了,這兩種方式有什麽區別呢?

繼承PureComponent時,不能再重寫shouldComponentUpdate,否則會引發警告(報錯截圖就不貼了,怪麻煩的)

Warning: CounterButton has a method called shouldComponentUpdate(). shouldComponentUpdate should not be used when extending React.PureComponent. Please extend React.Component if shouldComponentUpdate is used.

繼承PureComponent時,進行的是淺比較,也就是說,如果是引用類型的數據,只會比較是不是同一個地址,而不會比較具體這個地址存的數據是否完全一致

class ListOfWords extends React.PureComponent {
 render() {
     return <div>{this.props.words.join(',')}</div>;
 }
}
class WordAdder extends React.Component {

    state = {
        words: ['adoctors','shanks']
    };

    handleClick = () => {
        const {words} = this.state;
        words.push('tom');
        this.setState({words});
        console.log(words)
    }
    
    render() {
        const {words}=this.state;
        return (
            <div>
                <button onClick={this.handleClick}>click</button>
                <ListOfWords words={words} />
            </div>
        );
    }
}

上面代碼中,無論你怎麽點擊按鈕,ListOfWords渲染的結果始終沒變化,原因就是WordAdder的word的引用地址始終是同一個。

技術分享圖片

淺比較會忽略屬性或狀態突變的情況,其實也就是,數據引用指針沒變而數據被改變的時候,也不新渲染組件。但其實很大程度上,我們是希望重新渲染的。所以,這就需要開發者自己保證避免數據突變。

如果想使2中的按鈕被點擊後可以正確渲染ListOfWords,也很簡單,在WordAdder的handleClick內部,將 const words = this.state.words;

改為const words = this.state.words.slice(0);(這時的words是在原來state的基礎上復制出來一個新數組,所以引用地址當然變啦)

技術分享圖片

React.Component 與 React.PureComponent(React之性能優化)