我們都知道使用 React 讓我們的應用可以擁有非常好的效能,但背後裡 React 到底幫我們做了哪些努力呢?
今天就來初探一下 React 的渲染機制!
當我們開啟頁面時, React 透過 render 函式建構出一棵 DOM 樹出來,之後每次 state 或 props 變動時 ,React 會建構出另一個虛擬的 DOM 出來,來與真實的 DOM 做比較,這就是之前講過的 Virtual DOM的概念。
在執行 Diff 演算法時, React 有個假設前提:
基於這點假設,Diff 演算法只會針對同層節點進行比較
Diff 也極大的優化了這個比較的過程,將演算法複雜度從O(n^3)降低到O(n)。
如果父結點不同,React 不會再去比較子結點。這提高了比對的效率。
還記得好幾天前講的渲染過程嗎?
constructor -> render -> componentDidMount -> render(re-render by updating) -> componentDidUpdate -> componentWillUnmount
我們知道當 props 或 state 改動時會觸發元件的重新渲染(re-render)
而當父元件重新渲染時也會迫使它的子元件 re-render,然而我們清楚有些元件其實內容是寫死的,或是它的 props 根本就沒有改變,卻還是得依照慣例重新渲染,難道我們只能眼睜睜看著效能浪費嗎?
在 Day 9 介紹 lifecycle 時附上一張 React 組件的生命週期圖,還記得上面有個 shouldComponentUpdate 函式嗎?他就是拿來避免不必要的重新渲染的。
如果你在這個 function 中回傳 false,就不會重新呼叫 render function。
shouldComponentUpdate () {
return false;
}
也就是說當 componentDidMount 後再經過 render 後,元件就不會再重新渲染了。
但這樣寫死風險還是太大了,萬一真的需要重新渲染就被卡死在這了,因此一般來說我們會這樣寫:
shouldComponentUpdate(nextProps, nextState){
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
}
當 props 或 state 有變動時才回傳 true。
至於使用 shallowCompare 則是效能考量,有興趣的讀者可以自行研究一下囉!
其實 class based 的 PureCompponent 就是在背後幫我們加入了 shouldComponentUpdate 的判斷, 看到這你可能又會突破盲點了:“可是我們前幾天都用 functional 的 元件欸,不能用生命週期怎麼實現這件事?”
別急,明天就來介紹在 functional 元件中如何達成這件事。
最後提醒一下:當你確定你的 component props 或 state 會時常改變時,使用 shouldComponentUpdate 機制反而會多了不必要的 shollowCompare 使效能不增反減喔,所以使用時機必須非常仔細地去拿捏!