前端項目的開發過程中,經常會遇到性能優化的問題。項目比較小型還沒什麼太大的影響,當項目的規模達到一定程度的時候,性能問題就顯得比較突出了。
之前在做項目的過程中,並沒有怎麼在意組件的性能問題,最近看了一些文章,發現組件的性能優化並不是一件特別複雜的事情,只需要在寫代碼的時候稍微注意即可實現性能的優化。
React 15.3
中新增加了一個PureComponent
類,能夠減少render
函數的執行次數,避免不必要的組件渲染,實現性能上的優化,這其中的原理是什麼呢?
原理
當組件更新的時候,如果組件的props
和state
均爲發生改變,則不會觸發render
函數,省去了Virtual DOM
的生成和比對過程,達到提升性能的目的。底層原理就是,React
自動爲我們做了一層淺比較,判斷props
和state
是否發生變化,根據比較結果來決定組件是否更新:
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps)
|| !shallowEqual(inst.state, nextState);
}
淺比較這個點比較關鍵。我們都知道JavaScript
中的變量類型分爲基本類型(number
、string
、boolean
、undefined
、null
、symbol
)和引用類型(function
、object
、function
),基本類型的值保存在棧內存當中,引用類型的值保存在堆內存當中,棧內存中只保存指向堆內存的引用。那麼淺比較是什麼呢?
淺比較就是隻對棧內存中的數據進行比較
class App extends PureComponent {
state = {
items: [1, 2, 3]
}
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items });
}
render() {
return (
<div>
<ul>
{this.state.items.map(i => < li key={i}>{i}< /li>)}
</ul>
<button onClick={this.handleClick}>delete< /button>
</div>
)
}
}
上面這個就是一個很好的反例。使用了PureComponent
後,若props
或state
中的變量存在引用類型,且引用地址未發生改變,則不會觸發render
函數,即無論怎麼點擊delete
按鈕,都不會觸發組件的渲染。
因爲PureComponent
進行的是淺比較,即只對props
或state
的值或引用進行比較。
那麼如何修改上面這個組件,來避免這個問題呢?聰明人應該都已經想到了,修改state
的時候,改變item
變量的引用不就行了?
handleClick = () => {
const { item } = this.state;
var newItem = new Array(...item.pop());
this.setState({ item: newItem });
}
返回一個新的數組引用,並修改item
的引用,就能解決這個問題了。(方法有很多,可以使用數組的concat
方法與一個空數組連接返回一個新的數組,也可以使用數組的slice
方法截取數組前面的內容返回一個新的數組等等)
在React
的開發中,經常會使用到一個概念叫做Immutable
。
Immutable Data
就是一旦創建,就不能再被更改的數據。對Immutable
對象的任何修改或添加刪除操作都會返回一個新的 Immutable
對象。
具體的關於Immutable.js
的更多細節,可以移步:https://juejin.im/post/5ac437436fb9a028c97a437c
我們只需要知道,當我們試圖對Immutable
對象進行修改的時候,我們修改的結果會返回一個新的Immutable
對象,來時刻保證舊的Immutable
對象和新的Immutable
對象都可用。那麼不管我們怎麼修改,Immutable.js
都會返回一個新的Immutable
對象,這樣就能有效解決上述淺比較的問題。
總之,PureComponent
最好是搭配Immutable.js
進行使用,來達到性能優化的目的。