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

為了生成唯一id,React18專門引入了新Hook:useId

開發(fā) 前端
直到最近,React18推出了官方Hook——useId,雖然用法簡單,但背后的原理卻很有意思 —— 每個(gè)id代表該組件在組件樹中的層級結(jié)構(gòu)。

[[437140]]

大家好,我卡頌。

看看如下組件有什么問題:

  1. // App.tsx 
  2. const id = Math.random(); 
  3.  
  4. export default function App() { 
  5.   return <div id={id}>Hello</div> 

如果應(yīng)用是CSR(客戶端渲染),id是穩(wěn)定的,App組件沒有問題。

但如果應(yīng)用是SSR(服務(wù)端渲染),那么App.tsx會經(jīng)歷:

  1. React在服務(wù)端渲染,生成隨機(jī)id(假設(shè)為0.1234),這一步叫dehydrate(脫水)
  2. <div id="0.12345">Hello</div>作為HTML傳遞給客戶端,作為首屏內(nèi)容
  3. React在客戶端渲染,生成隨機(jī)id(假設(shè)為0.6789),這一步叫hydrate(注水)

客戶端、服務(wù)端生成的id不匹配!

事實(shí)上,服務(wù)端、客戶端無法簡單生成穩(wěn)定、唯一的id是個(gè)由來已久的問題,早在15年就有人提過issue:

Generating random/unique attributes server-side that don't break client-side mounting[1]

直到最近,React18推出了官方Hook——useId,才解決以上問題。他的用法很簡單:

  1. function Checkbox() { 
  2.   // 生成唯一、穩(wěn)定id 
  3.   const id = useId(); 
  4.   return ( 
  5.     <> 
  6.       <label htmlFor={id}>Do you like React?</label> 
  7.       <input type="checkbox" name="react" id={id} /> 
  8.     </> 
  9.   ); 
  10. ); 

雖然用法簡單,但背后的原理卻很有意思 —— 每個(gè)id代表該組件在組件樹中的層級結(jié)構(gòu)。

本文讓我們來了解useId的原理。

React18來了,一切都變了

這個(gè)問題雖然一直存在,但之前一直可以使用自增的全局計(jì)數(shù)變量作為id,考慮如下例子:

  1. // 全局通用的計(jì)數(shù)變量 
  2. let globalIdIndex = 0; 
  3.  
  4.  
  5. export default function App() { 
  6.   const id = useState(() => globalIdIndex++); 
  7.   return <div id={id}>Hello</div> 

只要React在服務(wù)端、客戶端的運(yùn)行流程一致,那么雙端產(chǎn)生的id就是對應(yīng)的。

但是,隨著React Fizz(React新的服務(wù)端流式渲染器)的到來,渲染順序不再一定。

比如,有個(gè)特性叫 Selective Hydration,可以根據(jù)用戶交互改變hydrate的順序。

當(dāng)下圖左側(cè)部分在hydrate時(shí),用戶點(diǎn)擊了右下角部分:

此時(shí)React會優(yōu)先對右下角部分hydrate:

關(guān)于Selective Hydration更詳細(xì)的解釋見:New Suspense SSR Architecture in React 18[2]

如果應(yīng)用中使用自增的全局計(jì)數(shù)變量作為id,那么顯然先hydrate的組件id會更小,所以id是不穩(wěn)定的。

那么,有沒有什么是服務(wù)端、客戶端都穩(wěn)定的標(biāo)記呢?

答案是:組件的層次結(jié)構(gòu)。

useId的原理

假設(shè)應(yīng)用的組件樹如下圖:

不管B和C誰先hydrate,他們的層級結(jié)構(gòu)是不變的,所以「層級」本身就能作為服務(wù)端、客戶端之間不變的標(biāo)識。

比如B可以使用2-1作為id,C使用2-2作為id:

  1. function B() { 
  2.   // id為"2-1" 
  3.   const id = useId(); 
  4.   return <div id={id}>B</div>; 

實(shí)際需要考慮兩個(gè)要素:

1. 同一個(gè)組件使用多個(gè)id

比如這樣:

  1. function B() { 
  2.   const id0 = useId(); 
  3.   const id1 = useId(); 
  4.   return ( 
  5.     <ul> 
  6.       <li id={id0}></li> 
  7.       <li id={id1}></li> 
  8.     </ul> 
  9.   ); 

2. 要跳過沒有使用useId的組件

還是考慮這個(gè)組件樹結(jié)構(gòu):

如果組件A、D使用了useId,B、C沒有使用,那么只需要為A、D劃定層級,這樣就能「減少需要表示層級」。

在useId的實(shí)際實(shí)現(xiàn)中,層級被表示為「32進(jìn)制」的數(shù)。

之所以選擇「32進(jìn)制」,是因?yàn)檫x擇盡可能大的進(jìn)制會讓生成的字符串盡可能緊湊。比如:

  1. const a = 18; 
  2.  
  3. // "10010" length 5 
  4. a.toString(2)    
  5.  
  6. //  "i" length 1 
  7. a.toString(32)   

具體的useId層級算法參考useId[3]

總結(jié)

React源碼內(nèi)部有多種棧結(jié)構(gòu)(比如用于保存context數(shù)據(jù)的棧)。

useId 棧的邏輯是其中比較復(fù)雜的一種。

誰能想到用法如此簡單的API背后,實(shí)現(xiàn)起來居然這么復(fù)雜?

React團(tuán)隊(duì)搗鼓「并發(fā)特性」,真挺不容易的...

參考資料

[1]Generating random/unique attributes server-side that don't break client-side mounting:

https://github.com/facebook/react/issues/4000

[2]New Suspense SSR Architecture in React 18:

https://github.com/reactwg/react-18/discussions/37

[3]useId:

https://github.com/facebook/react/pull/22644

 

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

2021-11-01 19:49:55

React組件模式

2021-06-22 07:45:57

React18startTransiReact

2021-06-22 07:30:07

React18Automatic b自動(dòng)批處理

2021-06-16 06:05:25

React18React

2022-03-16 17:01:35

React18并發(fā)的React組件render

2024-07-16 09:51:39

HTMLHookReact

2023-03-21 08:31:13

ReconcilerFiber架構(gòu)

2022-03-30 14:22:55

ReactReact18并發(fā)特性

2022-02-28 10:30:03

架構(gòu)代碼Native

2022-04-27 07:37:42

ReactReact18

2022-05-16 08:00:55

ReactReact 18數(shù)組

2024-04-01 13:08:24

唯一IDC#后端

2022-02-23 07:09:30

分布式ID雪花算法

2022-10-14 08:45:54

2024-04-24 11:00:05

React 18Fiber

2023-03-28 07:59:57

ReactReconciler

2022-04-18 08:57:32

React 18前端

2022-03-25 08:31:09

ReactReact 18升級

2022-07-06 15:07:47

React開發(fā)

2021-08-22 17:27:50

KDE PlasmaWindows概覽效果
點(diǎn)贊
收藏

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