這個 Lifecycle 其實非常直覺,看字面意思就是說「 決定 Lifecycle 是不是該 update ? 」
它在被呼叫的時間點為:改變 state 之後、執行 render() 之前。
所以如果沒有特別指定的話,預設會回傳 true。
以下是一個按 click me 按鈕會增加 counter 的小程式:
const Counter = props => {
return <div>{props.counter}</div>;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
counter: 1
}
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
counter: this.state.counter + 1
})
}
shouldComponentUpdate() {
console.log('shouldComponentUpdate is called'); // => 出現 1.
return true; // => 就是預設值,有寫沒寫都一樣
}
render() {
console.log('render'); // => 出現 2.
const {isShow} = this.state;
return (
<div>
<button onClick={this.handleClick}>Click me</button>
<Counter counter={this.state.counter}/>
</div>
)
}
}
render()會發現每按一下按鈕,console 會依序出現 shouldComponentUpdate is called 跟 render,代表先執行 shouldComponentUpdate 再執行 render。
那如果我把 shouldComponentUpdate() 回傳值改為 false 呢?
會發現按鈕突然無法 render 了,沒錯!
shouldComponentUpdate() 的回傳值決定了 「 當 Component 的 state 改變時,要不要去 call render() function 」
那既然 state 改變,不就要更新 UI 嗎? 還是說有什麼情況要把回傳值改成 false 呢?
有的,當遇到以下兩種情況,可以使用參數 nextProps & nextState 來進行檢查:
state or props 是否有更新,沒有更新就不必要浪費資源重新渲染nextProps & nextStatenextState 改變後的 statenextState 就是改變後的 state,所以我們可以依據 state 的狀態,去決定要不要 call render(),例如以下改成,如果 counter 超過 3,畫面就不要再有變動:
shouldComponentUpdate(nextProps, nextState) {
console.log('nextState: ', nextState);
if (nextState.counter > 3) return false; // => 超過 3 就不要 call render()
return true;
}
看 console 可以知道,實際上 counter 已經增加到 6 了,但畫面上的 counter 數量還是停留在 3

nextProps 改變後的 propsnextProps 跟 nextState 很像,只是目標是 props,實際的用途比較常拿來做檢查用。
假設我們有個 <Title /> Component,外面還有包一個 Component。
<Title /> 本身並不常更新,但如果 parent Component 要 call render(),children Component 也會跟著 render()。
所以當 <Title /> 本身狀態並沒有改變的話,其實是沒必要的動作,此時就很適合用 nextProps 來進行檢查。
class Title extends Component {
shouldComponentUpdate(nextProps, nextState) {
// => 改變後的 props 跟原本一樣的話就不要 call render()
if (nextProps.title !== this.props.title) return true;
return false;
// [ 注意 ] 以下錯誤寫法: 不能只寫一個情況。
// if (nextProps.title === this.props.title) return false;
}
render() {
console.log('render title');
return <div>{this.props.title}</div>
}
}
PureComponent以上可以知道 shouldComponentUpdate 能夠幫助我們做兩件事:
render()props or state 沒有變動時,不要 render()就第 2 個條件來說,難道每次都要手動比對,沒有更方便的作法嗎?
有的!相較於以前介紹過的 React.Component 跟 functional Component,還有一個叫做 「 PureComponent 」。
它的方便之處在於會幫你做 shallowly compares,意思是說會自動偵測 props or state 的變動,沒有更新就不會 call render()。
你可以把以下兩種寫法視為相同的:
// 1. 使用 PureComponent 會自動 shallowly compares
class Title extends PureComponent {
render() {
...
}
}
// 2. 自己寫 shouldComponentUpdate 判斷
class Title extends Component {
shouldComponentUpdate(nextProps, nextState){
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
}
render() {
...
}
}
這樣 PureComponent 聽起來不是超棒的嗎? 全部改成 PureComponent 就好了啊!
沒有這麼萬用喔,最好符合以下兩個條件,才使用 PureComponent:
state or props 很少變動的元件不然因為每次都進行 shallowEqual() 比對,如果元件一直頻繁更新,根本沒必要阻止 render(),到頭來反而會拖慢效率。
state or props結構簡單的情況因為 PureComponent 只會幫你做 shallowEqual(),如果是多層的陣列或物件並沒有用處
所以結構複雜的話可以考慮用 shouldComponentUpdate 搭配 library,例如 Immutable.js
參考資料:
( 以上內容大部分是 程式導師實驗計畫第三期 的學習筆記,如有錯誤歡迎糾正,非常感謝 🤓 )
Written on September 12th, 2019 by Yakim shu