React性能優(yōu)化必知必會(huì)

tips:歡迎關(guān)注我在github的博客點(diǎn)擊查看 。

使用React.pureComponent,React.memo做性能優(yōu)化

講這兩個(gè)api前需要提及React組件的更新,看這圖:

image

如果shouldComponentUpdate 返回false,那就一定不用rerender(重新渲染 )更新這個(gè)組件了,不用執(zhí)行調(diào)用render函數(shù),返回React elements去做比對(duì)(vdoms diff),而且這個(gè)組件的子組件也不用去調(diào)用shouldComponentUpdate判斷是否要更新了,因?yàn)楦附M件沒更新(自己也沒改變state)。但是如果shouldComponentUpdate 返回true,會(huì)進(jìn)行組件的React elements比對(duì),如果相同,則不用真實(shí)rerender這個(gè)組件,否則會(huì)rerender。

React.pureComponent

React.PureComponent,字面意思就是純組件,可類比存函數(shù)概念,所以當(dāng)有一致的渲染輸入(props和state)時(shí),因?yàn)橛型瑯拥匿秩拘Ч跃筒籸erender了,以此優(yōu)化性能。

React.Component是react的普通類組件,有個(gè)生命周期:在重新渲染之前應(yīng)調(diào)用shouldComponentUpdate。在初始渲染之后,當(dāng)接收到新的props或state時(shí),在重新渲染之前應(yīng)調(diào)用shouldComponentUpdate()。默認(rèn)為true。

而React.PureComponent與React.Component之間的區(qū)別在于,React.Component雖然可以在shouldComponentUpdate()這個(gè)生命周期中進(jìn)行自定義比較決定是否rerender,這樣可以做性能優(yōu)化。但是React.PureComponent的shouldComponentUpdate默認(rèn)內(nèi)置去淺比較prop和state來(lái)決定要不要rerender組件,解決了大量在Component雖然可以在shouldComponentUpdate寫差不多模板代碼的問題。

React.memo

React.pureComponent 服務(wù)于class組件,React.memo服務(wù)于函數(shù)組件,兩者服務(wù)對(duì)象不同,功能相同。有點(diǎn)不同的是,React.memo只會(huì)淺比較props,以前函數(shù)式組件是stateless的,所以淺比較props也就夠了,現(xiàn)依舊如此,useState hook帶來(lái)的state改變和useContext hook帶來(lái)的context改變,React.memo包(這貨是個(gè)高階組件)的組件仍會(huì)rerender。而且React.memo可以傳第二個(gè)參數(shù)來(lái)實(shí)現(xiàn)類似shouldComponentUpdate的功能自定義決定組件是否rerender => React.memo(MyComponent, areEqual);。當(dāng)然,return 值的意義兩者反著來(lái)。

結(jié)論

也就是React.PureComponent與React.memo默認(rèn)幫你用淺比較去決定要不要rerender,做性能優(yōu)化。

當(dāng)然,這邊要注意不要mutable地去改動(dòng)兩者的props或者PureComponent的state,這樣淺比較的結(jié)果為false,也就是這樣你就算改了也不會(huì)rerender, 除非調(diào)用forceUpdate()強(qiáng)制更新。

可是,這樣很多同學(xué)就會(huì)有事沒事就React.PureComponent,React.memo一把梭,好像吃不用錢的蜜糖。但是,甲之蜜糖 乙之砒霜,并不是所有場(chǎng)合都適合使用這兩個(gè)東東,用pureComponent會(huì)進(jìn)行淺比較state和props,這個(gè)比較也是需要開銷的,所以當(dāng)你知道組件一定需要重新渲染時(shí),就不要用pureComponent或者shouldComponentUpdate去做淺比較了,shouldComponentUpdate默認(rèn)值為true,省了這個(gè)淺比較,直接去比較React元素有沒有變,沒有變就不更新,有變才更新。

以下內(nèi)容來(lái)自React開發(fā)團(tuán)隊(duì)

If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want to rerender, all of the time spent checking whether you should have rerendered is wasted.

image

旦總還專門發(fā)推 (不是朱一旦,手動(dòng)狗頭)

使用react hook: useCallback, useMemo做性能優(yōu)化

這兩個(gè)因?yàn)樽饔糜悬c(diǎn)類似,都是用記憶計(jì)算結(jié)果來(lái)避免render的時(shí)候重新做一些計(jì)算,節(jié)省開銷。不同的是,useMemo是記憶值,也就是返回值:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

而useCallback是記憶函數(shù),也就是返回一個(gè)函數(shù),

const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b],);

useCallback(fn, deps) 等同于 useMemo(() => fn, deps).

而且我原以為會(huì)緩存之前多次計(jì)算過的東西,沒想到測(cè)試了下,只會(huì)緩存記憶上一次的,所以只有上一次和本次的依賴值相同時(shí),才會(huì)讀取上一次的計(jì)算結(jié)果,但是上一次之前的就算有跟本次的依賴值相同的,依舊要重新計(jì)算。如下圖

image.png

useCallback 可以確保在重新渲染之間那個(gè)回調(diào)不會(huì)發(fā)生變化,除非依賴(第二個(gè)參數(shù))改變

舉個(gè)例子

image

圖中RenderCallLogCallControl組件里面有一個(gè)onTransfer方法,如果不寫useCallback,那么每次RenderCallLogCallControl組件rerender,也就是這個(gè)函數(shù)組件會(huì)被重新執(zhí)行一次,因而onTransfer會(huì)跟著被重新創(chuàng)建,就算onTransfer還是一樣的函數(shù)內(nèi)容,但實(shí)際上引用地址不一樣,那么EvSmallCallControl和其子組件TransferCallButton接收到onTransfer的onTransfer prop即有變動(dòng),該組件因此也會(huì)rerender。

這種情況并不想因?yàn)閛nTransfer被重復(fù)創(chuàng)建而rerender組件,性能浪費(fèi),那么可以用useCallback把這個(gè)onTransfer函數(shù)memo起來(lái),讓其不會(huì)變動(dòng)(除非依賴transferRef改變), prop有onTransfer的組件也不會(huì)因此多做沒必要的rerender。

reference

Deep dive with the React DevTools profiler
Introducing the React Profiler
Optimizing Performance
React Top-Level API
should-i-use-react-purecomponent-everywhere

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容