第11章 性能優化
Reactde Dom diff算法使我們能夠在任意時間點高效地重新繪制整個用戶界面,并保證最小程度的DOM改變,然而,也存在需要對組件進行細致優化的情況,這時就需要渲染一個新的DOM來讓應用運行得更加高效。
shouldComponentUpdate
當一個組件更新時,無論是設置了新的props還是調用了setState方法,或者forceUpdate方法,React都會調用該組件所有的子組件的render方法。在大多數時候這樣的操作都沒有問題,但是在組件樹深度嵌套或是render方法十分復雜的頁面上,這可能會帶來些許延遲。
有時候組件的render方法會在不必要的情況下被調用。比如:組件渲染的過程中,并沒有使用props或者state的值,或者組件的props或者state并沒有在父組件重新渲染時發生改變。這意味著重新渲染這個組件會得到和已知虛擬DOM一模一樣的結果,這樣的計算過程是沒有必要的。
React提供了一個組件的生命周期方法shouldComponentUpdate,我們可以使用它來幫助React正確判斷是否需要調用組件的render方法。
shouldComponentUpdate方法返回一個布爾值。如果返回false就是告訴React不要調用組件的渲染方法,并使用之前渲染好的虛擬DOM;如果返回true則是讓React調用組件的渲染方法并計算出新的虛擬DOM。在默認情況下,shouldComponentUpadte方法永遠都會返回true,因此組件總是會調用render方法。
組件首次被渲染時,shouldComponentUpdate方法并不會被調用,shouldComponentUpdate方法接受兩個參數,即新的props和新的state,以幫助你決定是否應該重新渲染。
不可變性輔助插件
在需要比較對象以確定是否更新時,使用不可變得數據結構讓你的shouldComponentUpdate方法變得更加簡單。我們可以使用React.addons.update來確保<SurverEditor />
組件得不可變性。
React.addons.update接受一個數據結構和一個配置對象。你可以在配置對象中傳入$slice、$push、$unshift、$set和$apply
。
深入調查拖慢你應用的部分
正如我們在前幾小節中提到的那樣,給組件添加一個自定義的shouldComponentUpdate方法能夠在很大程度上優化程序。
React.addons.Perf插件能夠幫助我們找到添加shouldComponentUpdate方法的最佳位置。
鍵(Key)
多數時候,你會看到列表中使用key屬性的情況,它的作用是給React提供一種除組件類之外的識別一個組件的方法。舉個例子:假設有一個div組件,它的key屬性是foo,后續又將它改成了bar,那么React就會跳過DOM diff,同時完全放棄div所有的子元素,并重新從頭開始渲染。
在渲染大型子樹以避免diff計算時,這樣的設計很有用——因為這種計算就是在浪費時間。除了告訴React什么時候拋棄一個節點之外,很多情況下key還可以在元素順序改變時候使用,舉個例子:
var items=sortBy(this.state.sortingAlgorithm,this.props,items);
return items.map(funciton (item){return <img src={item.src}/};
});
如果順序發生改變,React會對元素進行diff操作,并確定出最高效的操作是改變其中幾個img元素的src屬性。這樣的結論其實是非常低效的,同時可能會導致瀏覽器查詢緩存,甚至導致新的網絡請求。
要解決這個問題,我們可以給每個img元素簡單的添加一些獨一無二的字符串或者數字。?return <img src={item.src} key={item.id}/>
;
這樣React得出的結論就不是改變src屬性,而是使用insertBefore操作,而這個操作是移動DOM節點最高效的方法。
除了改變順序外,這個操作同樣適用于插入操作(不包括向末尾元素后面插入)。如果沒有正確的key屬性,在數組開頭插入一個項目會導致后續的<img>
標簽的src屬性發生改變。
值得注意的一點是,盡管key看似被作為一個屬性傳入了,但其實在組件的任何位置都無法實際獲取到它。
總結
- 將shouldComponentUpdate返回值改為true或者false以提升性能。
- 使用React.addons.Perf來診斷緩慢或不必要的渲染。
- 使用key來幫助,React識別列表中所有子組件的最小變化。