React由於他的性能而著名。由於他有一個虛擬DOM層而且只有在須要時才更新真實DOM。即便是一樣地信息這也比一直直接更新DOM要快不少。可是,React的智能僅此而已(目前爲止),咱們的任務是知道React的預期行爲以及限制,這樣咱們纔不會意外損失性能。javascript
咱們須要關注的一方面是React如何決定何時從新渲染組件。不是從新渲染DOM節點,只是調用render
方法來改變虛擬DOM。咱們能夠經過告訴React何時須要渲染何時不須要渲染來幫助React。讓咱們依次來看看這些。html
只有在組件的state變化時纔會出發組件的從新渲染。狀態的改變能夠由於props
的改變,或者直接經過setState
方法改變。組件得到新的狀態而後React決定是否應該從新渲染組件。不幸的是,React難以置信簡單地將默認行爲設計爲每次都從新渲染。java
組件改變?從新渲染。父組件改變?從新渲染。一部分沒有致使視圖改變的props改變?從新渲染。react
class Todo extends React.Component { componentDidMount() { setInterval(() => { this.setState(() => { console.log('setting state'); return { unseen: "does not display" } }); }, 1000); } render() { console.log('render called'); return (<div>...</div>); } }
在這個(很是刻意的)例子中,Todo
將會每秒從新渲染依次,即便render
方法根本沒有使用unseen
。事實上,unseen
值甚至都不改變。你能夠在CodePen裏查看這個例子的實際版本。git
好吧,可是每次都從新渲染沒有什麼幫助。github
個人意思是,我很是感謝React的細心謹慎。若是狀態改變可是組件沒有正確渲染的話更糟。權衡之下,每次都從新渲染絕對是一個安全的選擇。安全
可是從新渲染的時間成本看起來很是昂貴(例子裏很是誇張地表現了出來)。性能優化
是的,在沒必要要的時候從新渲染會浪費循環而且不是一個好的想好。可是,React不能知道何時能夠安全的跳太重新渲染,因此React不管是否重要每次都從新渲染。工具
咱們如何告訴React跳太重新渲染?性能
那就是第二點要說的內容。
shouldComponentUpdate
方法shouldComponentUpdate
方法默認返回true
,這就是致使每次更新都從新渲染的緣由。可是你能夠在須要優化性能時重寫這個方法來讓React更智能。比起讓React每次都從新渲染,你能夠告訴React你何時不像觸發從新渲染。
當React將要渲染組件時他會執行shouldComponentUpdate
方法來看它是否返回true
(組件應該更新,也就是從新渲染)。因此你須要重寫shouldComponentUpdate
方法讓它根據狀況返回true
或者false
來告訴React何時從新渲染何時跳太重新渲染。
當你使用shouldComponentUpdate
方法你須要考慮哪些數據對與從新渲染重要。讓咱們回到這個例子。
正如你所看到的,咱們只想在title
和done
屬性改變的時候從新渲染Todo
。咱們不關心unseen
是否改變,因此我沒有把它包含在shouldComponentUpdate
方法中。
當React渲染Todo
組件(經過setState
觸發)他會首先檢查狀態是否改變(經過props
和state
)。假設狀態改變了(由於咱們顯式地調用了setState
因此這會發生)React會檢查Todo
的shouldComponentUpdate
方法。React會根據shouldComponentUpdate
方法返回值爲true
或者false
來決定從哪裏渲染。
更新後的代碼仍然會每秒調用一次setState
可是render
只有在第一次加載時(或者title
或done
屬性改變後)纔會調用。你能夠在這裏看到。
看起來有不少工做去作。
是的,這個例子很是冗長由於有兩個屬性(title
和done
)須要關注而且只有一個能夠忽略(unseen
)。根據你的數據可能僅檢查一個或兩個屬性而且忽略其餘會更有意義。
重要提示
當子組件的的state變化時, 返回false並不能阻止它們重渲染。
– Facebook的React文檔
這做用於子組件的狀態而不是他們的props
。因此若是一個子組件內部管理了一些他本身的狀態(使用他本身的setState
),這仍然會更新。可是若是父組件的shouldComponentUpdate
方法返回了false
就不會傳遞更新後的props
給他的子組件,因此子組件不會重渲染,即便他們的props
變化了。
編寫而且在shouldComponentUpdate
方法中運行計算的時間成本可能會很昂貴,因此你須要確保值得作。在寫shouldComponentUpdate
方法前你能夠測試React一個週期默認會消耗多少時間。有了這個信息作參考,在作性能優化時你能夠作一個不盲目的決定。
使用React的性能工具去發現浪費的週期:
Perf.start() // Do the render Perf.stop() Perf.printWasted()
哪個組件浪費了不少渲染週期?你怎麼經過shouldComponentUpdate
方法讓他們更智能?試着使用性能測試工具來比較他們的性能。