自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

奇怪的useMemo知識(shí)增加了

開(kāi)發(fā) 前端
這篇文章提到的useMemo用法,相比Vue,React更靈活,開(kāi)發(fā)過(guò)程中需要開(kāi)發(fā)者注意更多細(xì)節(jié)。要完全了解React,可能需要學(xué)習(xí)一些源碼層面的知識(shí)。

[[380079]]

 作為「性能優(yōu)化」手段,一般用useMemo緩存函數(shù)組件中比較消耗性能的計(jì)算結(jié)果:

  1. function App() { 
  2.   const memoizedValue = useMemo( 
  3.     () => computeExpensiveValue(a, b), 
  4.     [a, b] 
  5.   ); 
  6.   // ... 

只有在依賴項(xiàng)改變后才會(huì)重新計(jì)算新的memoizedValue。

你有沒(méi)有想過(guò),如果用useMemo緩存函數(shù)組件的返回值,會(huì)怎么樣呢?

舉個(gè)例子

我們有個(gè)全局context —— AppContext。

由于同學(xué)們偷懶,隨著項(xiàng)目的迭代,新增的context都選擇放在AppContext里,導(dǎo)致AppContext包含的內(nèi)容越來(lái)越多。

現(xiàn)在我們有個(gè)Tree組件,他會(huì)渲染一個(gè)很耗性能的大組件ExpensiveTree。

  1. function Tree() { 
  2.   let appContextValue = useContext(AppContext); 
  3.   let theme = appContextValue.theme; 
  4.  
  5.   return <ExpensiveTree className={theme} />; 

該組件內(nèi)部依賴AppContext中的theme狀態(tài)。

由于AppContext中包含很多與theme無(wú)關(guān)的state,導(dǎo)致每次其他無(wú)關(guān)的state更新,Tree都會(huì)重新render,進(jìn)而ExpensiveTree組件也重新render。

現(xiàn)在這個(gè)優(yōu)化任務(wù)交到了你手上,該怎么辦呢?

優(yōu)化ExpensiveTree

這時(shí)候,useMemo就能派上用場(chǎng):

  1. function Tree() { 
  2.   let appContextValue = useContext(AppContext); 
  3.   let theme = appContextValue.theme; 
  4.  
  5.   return useMemo(() => { 
  6.     return <ExpensiveTree className={theme} />; 
  7.   }, [theme]) 

我們將返回的ExpensiveTree作為useMemo返回值,theme作為依賴。

這樣,即使AppContext改變導(dǎo)致Tree反復(fù)render,ExpensiveTree也只會(huì)在theme改變后render。

[[380080]]

原理解析

要理解這么做有效的原因,需要了解三點(diǎn):

  1. useMemo返回值是什么
  2. 函數(shù)組件的返回值是什么
  3. React組件在什么時(shí)候render

回答第一個(gè)問(wèn)題:useMemo會(huì)將第一個(gè)參數(shù)(函數(shù))的返回值保存在組件對(duì)應(yīng)fiber中,只有在依賴項(xiàng)(第二個(gè)參數(shù))變化后才會(huì)重新調(diào)用第一個(gè)參數(shù)(函數(shù))計(jì)算一個(gè)新值。

回答第二個(gè)問(wèn)題:函數(shù)組件的返回值是JSX對(duì)象。

同一個(gè)函數(shù)組件調(diào)用多次,返回的是多個(gè)「不同」的JSX對(duì)象(即使props未變,但JSX是新的引用)。

按照以上兩個(gè)回答,我們可以得出結(jié)論:

  • 以上useMemo用法實(shí)際上在函數(shù)組件對(duì)應(yīng)的fiber中緩存了一個(gè)完整的JSX對(duì)象

第三個(gè)問(wèn)題,函數(shù)組件需要同時(shí)滿足如下條件才不會(huì)render:

1 oldProps === newProps

前后兩次更新props全等,注意是「全等」。

2 組件context沒(méi)有變化

3 workInProgress.type === current.type

組件更新前后fiber.type未變化,比如div沒(méi)有變?yōu)閜。

4 !includesSomeLane(renderLanes, updateLanes)

當(dāng)前fiber上不存在更新,或者存在更新但優(yōu)先級(jí)低。

  • 更詳細(xì)的解釋,可以參考這篇文章:React組件到底什么時(shí)候render?

當(dāng)我們不使用useMemo包裹返回值,每次Tree render返回的都是全新的JSX對(duì)象。

所以對(duì)于ExpensiveTree,oldProps !== newProps。

再看2:ExpensiveTree內(nèi)部context沒(méi)變,滿足

再看3:ExpensiveTree更新前后type都是ExpensiveTree,滿足

再看4: ExpensiveTree內(nèi)沒(méi)有狀態(tài)更新,滿足

所以,當(dāng)我們使用useMemo包裹ExpensiveTree后,當(dāng)theme不變,每次Treerender后返回的都是同一個(gè)JSX對(duì)象,滿足第一條。

基于這個(gè)原因,ExpensiveTree不會(huì)render。

總結(jié)

這篇文章提到的useMemo用法,并未在官網(wǎng)文檔中體現(xiàn),而是在#15156[1]中由Dan介紹。

相比Vue,React更靈活,開(kāi)發(fā)過(guò)程中需要開(kāi)發(fā)者注意更多細(xì)節(jié)。要完全了解React,可能需要學(xué)習(xí)一些源碼層面的知識(shí)。

參考資料

[1]#15156:

https://github.com/facebook/react/issues/15156#issuecomment-474590693

 

責(zé)任編輯:姜華 來(lái)源: 魔術(shù)師卡頌
相關(guān)推薦

2021-10-09 09:35:28

開(kāi)發(fā)JavaScript 代碼

2021-02-22 10:23:01

程序員技能開(kāi)發(fā)者

2010-10-19 11:30:16

IT培訓(xùn)

2009-06-11 17:18:23

EJB3.1Singleton B

2023-01-16 18:22:53

Discourse開(kāi)源

2012-04-30 20:44:55

2022-02-10 10:52:09

網(wǎng)絡(luò)攻擊網(wǎng)絡(luò)安全漏洞

2015-10-19 17:36:19

MOST內(nèi)核Linux

2023-05-21 23:40:03

開(kāi)源圖文模型

2020-12-29 09:37:41

漏洞網(wǎng)絡(luò)安全網(wǎng)絡(luò)攻擊

2020-05-15 19:25:09

HTML5JavaScript前端

2023-10-04 09:38:55

Firefox瀏覽器

2022-05-30 16:19:40

惡意軟件僵尸網(wǎng)絡(luò)網(wǎng)絡(luò)攻擊

2009-01-12 16:25:40

電子郵件數(shù)據(jù)管理法規(guī)遵從

2023-12-15 14:57:39

ReactNativeFabric

2018-07-11 04:16:16

2022-11-04 12:27:35

2021-03-18 08:03:58

SteamMesa緩存

2022-08-08 10:42:39

物聯(lián)網(wǎng)物聯(lián)網(wǎng)技術(shù)

2018-09-25 10:46:15

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)