>React.PureComponent是React在15.3版本添加的一個與React.Component同級的API;
React.memo是React 16.6版本新增的一個高階函數API。
這兩個API本質上都是為了性能優化而生,通過使用這兩個API可以減少頁面不必要的重新渲染,提高頁面性能。
### PureComponent
#### 最基本的應用
父組件:
```javascript
import React, { Component } from 'react';
import PureTest from './pureComp';
const titleArr = ['第一個標題', '第二個標題', '第三個標題'];
class PureComp extends Component {
state = {
title: '第一個標題',
}
componentDidUpdate() {
console.log(`父組件更新,標題為${this.state.title}`);
}
handleClick = () => {
this.setState({
title: titleArr[Math.round(Math.random() * 2)],
});
}
render() {
const { title } = this.state;
return (
<div>
<button onClick={this.handleClick.bind(this)}>更改state</button>
<PureTest title={title} />
</div>
);
}
}
export default PureComp;
```
子組件
```javascript
import React, { PureComponent } from 'react';
class PureTest extends PureComponent {
componentDidUpdate() {
console.log(`pureComponent組件更新,標題為${this.props.title}`);
}
render() {
return (
<h1>{this.props.title}</h1>
);
}
}
export default PureTest;
```
點擊按鈕打印執行結果:

#### PureComponent判斷是否需要更新方法為淺比對



改進方法:

>[danger]基于這個特性我們應該避免在中引用純組件時寫出如下代碼
>```javascript
> // 避免寫{}作為默認值,因為每次使用{}時指向的內存地址都不一樣,在瀏覽器控制臺中輸入{}==={}就可以看到返回值為false
> <PureTestComp value={this.state.pureObj || {}} />
> // 有時候為了提高程序的健壯性,我們必須寫默認值,那么就將默認值抽出來做一個單獨的變量
> const defaultEmpty = {};
> <PureTestComp value={this.state.pureObj || defaultEmpty} />
>```
<br />
**總結及注意事項**
- 純組件與組件繼承自不同父類
- 純組件在比較props和state變動與否時使用的是淺比較,在我理解看來淺比較就是比較新的props和老的props中數據的key值是否相同以及key值指向內存的地址是否發生變動,因此
- Number,String等類型變動時因為內存地址直接變動,所以組件會更新
- Object、Array等數據類型,在不修改內存地址時純組件認為該數據沒有發生變動,因此當純組件需要傳遞一個對象或者數組作為props時,在修改數據時需要我們重新開辟一塊內存空間存儲變量。
- 在純組件中使用shouldComponentUpdate生命周期,組件會舍棄React提供的shallowEqual方法而使用我們設定的更新邏輯。
- 如果在純組件中只是部分使用了父組件傳遞的props且props是一個深層數據,這時建議不要使用純組件,在純組件中使用shouldComponentUpdate是一件很詭異的事情,違背了我們使用純組件的初衷,我們可以通過Component和shouldComponentUpdate結合使用來解決多次渲染問題。
>[warning]其實pureComponent組件還會判斷state是否發生了變動,但是在我看來使用pureComponent的場景在于純展示組件,且傳遞的props數據層級也應該盡可能的淺(因為是淺比較),不建議在pureComponent維護一套state,具體的shallowEqual算法如下
> ```javascript
>if (this._compositeType === CompositeTypes.PureClass) {
> shouldUpdate = !shallowEqual(prevProps, nextProps)
> || !shallowEqual(inst.state, nextState);
>}
>```
<br />
## React.memo
React.memo適用于函數式組件,相當于一個高階函數,將普通的函數式組件包裝成一個類似pureComponent的組件,React.memo接受兩個參數
- 第一個參數為要包裝的函數式組件
- 第二個參數為一個返回值為true或false的回調函數,用于控制組件的更新狀態
經過實驗,在只是用第一個參數時,react.memo表現和pureComponent表現是相同的,那么下來的內容主要是講使用第二個參數時的差異
經過React.memo包裝后的組件會增加一個類似shouldComponentUpdate的生命周期(只是類似,其實結果是截然相反的,后面會解釋),普通的函數式組件時沒有這個生命周期的,也就是說不使用react.memo時函數式組件的更新狀態是不可控的。
在官方文檔中,第二個參數被叫做areEquals,當沒有傳遞第二個參數時,React會自動進行淺比較然后判斷組件的狀態去更新組件。通過使用第二個參數,我們可以自己控制組件的更新狀態。

>[info]看了紅框里的代碼,肯定有人注意到第二個回調函數的返回值和shouldComponentUpdate是相反的,上面的代碼表示在回調函數中如果title相同時返回true,而不同時返回fasle,似乎與我們理解的不同。
其實這個問題在于我們對areEquals這個值的理解,在shouldComponentUpdate我們返回的是要不要更新,而<u>areEqulas值的意思為是不是相同的,在相同時即為true時我們不更新,在不同時即為fasle時我們更新組件</u>,也就是說第二個回調函數其實也可以理解為是一個shouldComponent<u>Not</u>Update生命周期