react 整個生命週期大概分爲三個階段:掛載階段、更新階段、銷燬階段,我們在談 react 優化的時候主要還是針對更新階段。
render
我們先來回顧一下 render 函數做了什麼事情
- 構建 Virtual DOM 樹
- diff 出差異化節點
- 根據 Virtual DOM 樹解析出 html 結構
- 將 html 結構掛載到真是 DOM 樹上
shouldComponentUpdate
該函數位於更新階段,在 render 之前。表示本次更新是否影響到當前組件,默認爲 true,會執行後續的 render 函數,即使最後經過 diff 發現沒有需要更新的地方。
所以我們可以在組件的 shouldComponentUpdate 鉤子裏,自己來判斷要不要更新,如果不需要就 return false,這樣就少了構建 Virtual Dom、diff 這些階段了,對性能提升有一定的幫助。如
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 99
};
}
shouldComponentUpdate(nextProps, nextState) {
if (nextState.count === this.state.count) {
return false; // 不參與 render 和 diff 過程
}
return true;
}
render () {
return (
<div id="container">{ this.state.count }</div>
)
}
}
PureComponent
上面的例子中,我們在 shouldComponentUpdate 中手動判斷了當前組件是否需要更新的邏輯。有了 PureComponent,想這種簡單的組件我們就不需要自己判斷了,直接讓組件繼承 React.PureComponent 就行了,應該 PureComponent 內部已經幫我們執行了 shouldComponentUpdate,如果發現 props 和 state 都沒有變化,那麼 return false,不參與更新。
但是注意:PureComponent 中的判斷是一種淺比較,也就是說如果你的 data 中的屬性全部只有一層(屬性值是基本類型),那麼沒問題。但是如果屬性值裏面是一個 Object 或者是一個 Array,那麼屬性值內部的變化,PureComponent 就無法感知了。所以組件的屬性值比較複雜的話,建議不要用 PureComponent。
屬性傳遞
在組件上綁定函數一般有以下幾種方式
- constructor 中綁定 this:this.handleClick = this.handleClick.bind(this);使用 <button onClick={this.handleClick}></button>
- 使用時綁定:<button onClick={this.handleClick.bind(this)}
- 箭頭函數:<button onClick={() => {this.handleClick()}}
- 組件本身方法使用箭頭函數:handleClick = () => {};使用 <button onClick={this.handleClick}></button>
推薦 1 和 4,2 和 3 在組件每次執行 render 時都會生成一個新的函數,在 diff 階段會經過淺比較判斷出屬性需要更新
合理利用 key
在更新階段,react 會通過組件的 key 值來進行新老節點的匹配。如果匹配到了,只需要更新屬性或者調整位置就行了,避免了組件的重新掛載。