React效能優化總結
react
的元件渲染分為初始化渲染和更新渲染
- 在初始化渲染的時候會呼叫根元件下的所有元件的
render
方法進行渲染,如下圖(綠色表示已渲染,這一層是沒有問題的)
但是當我們要更新某個子元件的時候,如下圖的綠色元件(從根元件傳遞下來應用在綠色元件上的資料發生改變)
我們的理想狀態是隻呼叫關鍵路徑上元件的render
但是 react
的預設做法是呼叫所有元件的 render
,再對生成的虛擬 DOM
進行對比,如不變則不進行更新。這樣的 render
和虛擬 DOM
的 對比 明顯是在浪費,如下圖(黃色表示浪費的 render
和虛擬 DOM
對比)
Tips
- 拆分元件是有利於複用和元件優化的
- 生成虛擬
DOM
並進行比對發生在render()
後,而不是render()
前
二、更新階段的生命週期
-
componentWillReceiveProps(object nextProps)
:當掛載的元件接收到新的props
時被呼叫。此方法應該被用於比較this.props
和nextProps
以用於使用this.setState()
執行狀態轉換。(元件內部資料有變化,使用state
,但是在更新階段又要在props
改變的時候改變state
,則在這個生命週期裡面) -
shouldComponentUpdate(object nextProps, object nextState)
: -boolean
當元件決定任何改變是否要更新到DOM
時被呼叫。作為一個 優化 實現比較this.props
和nextProps
、this.state
和nextState
,如果React
應該跳過更新,返回false
-
componentWillUpdate(object nextProps, object nextState
) :在更新發生前被立即呼叫。你不能在此呼叫this.setState()
-
componentDidUpdate(object prevProps, object prevState
) : 在更新發生後被立即呼叫。(可以在DOM
更新完之後,做一些收尾的工作)
Tips
-
React
的優化是基於shouldComponentUpdate
的,該生命週期預設返回true
,所以一旦prop
或state
有任何變化,都會引起重新render
三、shouldComponentUpdate
react
在每個元件生命週期更新的時候都會呼叫一個 shouldComponentUpdate(nextProps, nextState)
函式。它的職責就是返回 true
或 false
,true表示需要更新, false
表示不需要,預設返回為 true
,即便你沒有顯示地定義 shouldComponentUpdate
函式。這就不難解釋上面發生的資源浪費了
帶坑的寫法
-
{...this.props}
(不要濫用,請只傳遞component
需要的props
,傳得太多,或者層次傳得太深,都會加重shouldComponentUpdate
裡面的資料比較負擔,因此,也請慎用spread attributes(<Component {...props} />))
-
::this.handleChange()。(請將方法的bind一律置於constructor)
- 複雜的頁面不要在一個元件裡面寫完
- 請儘量使用
const element
-
map
裡面新增key
,並且key
不要使用index
(可變的) - 儘量少用
setTimeOut
或不可控的refs
、DOM
操作 - 資料儘可能簡單明瞭,扁平化
四、效能檢測工具
React.addons.Perf
react
官方提供一個外掛 React.addons.Perf
可以幫助我們分析元件的效能,以確定是否需要優化
react16
以前需要在專案中配置, react16
以後請看這篇文章,直接開啟控制檯的 perf
選項測試 ofollow,noindex">https://reactjs.org/docs/optimizing-performance.html#profiling-components-with-the-chrome-performance-tab
react16之前配置
- 安裝
react
效能檢測工具npm i react-addons-perf --save
,然後在./app/index.js
中
// 效能測試 import Perf from 'react-addons-perf' if (__DEV__) { window.Perf = Perf }
- 開啟
console
面板,先輸入Perf.start()
執行一些元件操作,引起資料變動,元件更新,然後輸入Perf.stop()
。(建議一次只執行一個操作,好進行分析) - 再輸入
Perf.printInclusive
檢視所有涉及到的元件render
,如下圖(官方圖片)
或者輸入 Perf.printWasted()
檢視下不需要的的浪費元件 render
優化前
優化後