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

React Hooks 的實(shí)現(xiàn)必須依賴 Fiber 么?

開(kāi)發(fā) 前端
現(xiàn)在,不止 react 中實(shí)現(xiàn)了 hooks,在 preact、react ssr、midway 等框架中也實(shí)現(xiàn)了這個(gè)特性,它們的實(shí)現(xiàn)就是不依賴 fiber 的。

React 的 hooks 是在 fiber 之后出現(xiàn)的特性,所以很多人誤以為 hooks 是必須依賴 fiber 才能實(shí)現(xiàn)的,其實(shí)并不是,它們倆沒(méi)啥必然聯(lián)系。

現(xiàn)在,不止 react 中實(shí)現(xiàn)了 hooks,在 preact、react ssr、midway 等框架中也實(shí)現(xiàn)了這個(gè)特性,它們的實(shí)現(xiàn)就是不依賴 fiber 的。

我們分別來(lái)看一下這些不同框架中的 hooks 都是怎么實(shí)現(xiàn)的:

react 如何實(shí)現(xiàn) hooks

react 是通過(guò) jsx 描述界面的,它會(huì)被 babel 或 tsc 等編譯工具編譯成 render function,然后執(zhí)行產(chǎn)生 vdom:

這里的 render function 在 React17 之前是 React.createElement:

在 React 17 之后換成了 jsx:

這個(gè) jsx-runtime 會(huì)自動(dòng)引入,不用像之前那樣每個(gè)組件都要保留一個(gè) React 的 import 才行。

render function 執(zhí)行產(chǎn)生 vdom:

vdom 的結(jié)構(gòu)是這樣的:

在 React16 之前,會(huì)遞歸渲染這個(gè) vdom,增刪改真實(shí) dom。

而在 React16 引入了 fiber 架構(gòu)之后就多了一步:首先把 vdom 轉(zhuǎn)成 fiber,之后再渲染 fiber。

vdom 轉(zhuǎn) fiber 的過(guò)程叫做 reconcile,最后增刪改真實(shí) dom 的過(guò)程叫做 commit。

為什么要做這樣的轉(zhuǎn)換呢?

因?yàn)?vdom 只有子節(jié)點(diǎn) children 的引用,沒(méi)有父節(jié)點(diǎn) parent 和其他兄弟節(jié)點(diǎn) sibling 的引用,這導(dǎo)致了要一次性遞歸把所有 vdom 節(jié)點(diǎn)渲染到 dom 才行,不可打斷。

萬(wàn)一打斷了會(huì)怎么樣呢?因?yàn)闆](méi)有記錄父節(jié)點(diǎn)和兄弟節(jié)點(diǎn),那只能繼續(xù)處理子節(jié)點(diǎn),卻不能處理 vdom 的其他部分了。

所以 React 才引入了這種 fiber 的結(jié)構(gòu),也就是有父節(jié)點(diǎn) return、子節(jié)點(diǎn) child、兄弟節(jié)點(diǎn) sibling 等引用,可以打斷,因?yàn)閿嗔嗽倩謴?fù)也能找到后面所有沒(méi)處理過(guò)的節(jié)點(diǎn)。

fiber 節(jié)點(diǎn)的結(jié)構(gòu)是這樣的:

這個(gè)過(guò)程可以打斷,自然也就可以調(diào)度,也就是 schdule 的過(guò)程。

所以 fiber 架構(gòu)就分為了 schdule、reconcile(vdom 轉(zhuǎn) fiber)、commit(更新到 dom)三個(gè)階段。

函數(shù)組件內(nèi)可以用 hooks 來(lái)存取一些值,這些值就是存在 fiber 節(jié)點(diǎn)上的。

比如這個(gè)函數(shù)組件內(nèi)用到了 6 個(gè) hook:

那么對(duì)應(yīng)的 fiber 節(jié)點(diǎn)上就有個(gè) 6 個(gè)元素的 memorizedState 鏈表:

通過(guò) next 串聯(lián)起來(lái):

不同的 hook 在 memorizedState 鏈表不同的元素上存取值,這就是 react hooks 的原理。

這個(gè)鏈表有創(chuàng)建階段和更新階段,所以你會(huì)發(fā)現(xiàn) useXxx 的最終實(shí)現(xiàn)都分為了 mountXxx 和 updateXxx:

這里的 mount 階段就是創(chuàng)建 hook 節(jié)點(diǎn)并組裝成鏈表的:

會(huì)把創(chuàng)建好的 hook 鏈表掛到 fiber 節(jié)點(diǎn)的 memorizedState 屬性上。

那更新的時(shí)候自然也就能從 fiber 節(jié)點(diǎn)上取出這個(gè) hook 鏈表:

這樣在多次渲染中,useXxx 的 api 都能在 fiber 節(jié)點(diǎn)上找到對(duì)應(yīng)的 memorizedState。

這就是 react hooks 的原理,可以看到它是把 hook 存在 fiber 節(jié)點(diǎn)上的。

那 preact 有什么不同呢?

preact 如何實(shí)現(xiàn) hooks

preact 是兼容 react 代碼的更輕量級(jí)的框架,它支持 class 組件和 function 組件,也支持了 hooks 等 react 特性。不過(guò)它沒(méi)有實(shí)現(xiàn) fiber 架構(gòu)。

因?yàn)樗饕紤]的是體積的極致(只有 3kb),而不是性能的極致。

剛才我們了解了 react 是把 hook 鏈表存放在 fiber 節(jié)點(diǎn)上的,那 preact 沒(méi)有 fiber 節(jié)點(diǎn),會(huì)把 hook 鏈表存在哪呢?

其實(shí)也很容易想到,fiber 只是對(duì) vdom 做了下改造用于提升性能的,和 vdom 沒(méi)啥本質(zhì)的區(qū)別,那就把 hook 存在 vdom 上不就行了?

確實(shí),preact 就是把 hook 鏈表放在了 vdom 上。

比如這個(gè)有 4 個(gè) hooks 的函數(shù)組件:

它的實(shí)現(xiàn)就是在 vdom 上存取對(duì)應(yīng)的 hook:

它沒(méi)有像 react 那樣把 hook 分為 mount 和 update 兩個(gè)階段,而是合并到一起處理了。

如果,它把 hooks 存在了 component.__hooks 的數(shù)組上,通過(guò)下標(biāo)訪問(wèn)。

這個(gè) component 就是 vdom 上的一個(gè)屬性:

也就是把 hooks 的值存在了 vnode._component._hooks 的數(shù)組上。

對(duì)比下 react 和 preact 實(shí)現(xiàn) hooks 的差異:

  • react 中是把 hook 鏈表存放在 fiberNode.memorizedState 屬性上,preact 中是把 hook 鏈表存放在 vnode._component._hooks 屬性上。
  • react 中的 hook 鏈表通過(guò) next 串聯(lián),preact 中的 hook 鏈表就是個(gè)數(shù)組,通過(guò)下標(biāo)訪問(wèn)。
  • react 把 hook 鏈表的創(chuàng)建和更新分離開(kāi),也就是 useXxx 會(huì)分為 mountXxx 和 updateXxx 來(lái)實(shí)現(xiàn),而 preact 中合并在一起處理的。

所以說(shuō),hooks 的實(shí)現(xiàn)并不依賴 fiber,它只不過(guò)是找個(gè)地方存放組件對(duì)應(yīng)的 hook 的數(shù)據(jù),渲染時(shí)能取到就行,存放在哪里是無(wú)所謂的。

因?yàn)?vdom、fiber 和組件渲染強(qiáng)相關(guān),所以存放在了這些結(jié)構(gòu)上。

像 react ssr 實(shí)現(xiàn) hooks,就既沒(méi)有存在 fiber 上,也沒(méi)有存在 vdom 上:

react ssr 如何實(shí)現(xiàn) hooks

其實(shí) react-dom 包除了可以做 csr 外,也可以做 ssr:

csr 時(shí)使用 react-dom 的 render 方法:

ssr 的時(shí)候使用 react-dom/server 的 renderToString 方法或 renderToStream 方法:

大家覺(jué)得 ssr 的時(shí)候會(huì)做 vdom 到 fiber 的轉(zhuǎn)換么?

肯定不會(huì)呀,fiber 是為了提高在瀏覽器中運(yùn)行時(shí)的渲染性能,把計(jì)算變成可打斷的,在空閑時(shí)做計(jì)算,才引入的一種結(jié)構(gòu)。

服務(wù)端渲染自然就不需要 fiber。

不需要 fiber 的話,它把 hook 鏈表存放在哪里呢?vdom 么?

確實(shí)可以放在 vdom,但是其實(shí)并沒(méi)有。

比如 useRef 這個(gè) hooks:

它是從 firstWorkInProgressHook 開(kāi)始的用 next 串聯(lián)的一個(gè)鏈表。

而 firstWorkInProgressHook 最開(kāi)始用 createHook 創(chuàng)建的第一個(gè) hook 節(jié)點(diǎn):

并沒(méi)有掛載到 vdom 上。

為什么呢?

因?yàn)?ssr 只需要渲染一次呀,又不需要更新,自然沒(méi)必要掛到 vdom 上。

只要每次處理完每個(gè)組件的 hooks 就清空一下這個(gè) hook 鏈表就行:

所以,react ssr 時(shí),hooks 是存在全局變量上的。

對(duì)比下 react csr 和 ssr 時(shí)的 hooks 實(shí)現(xiàn)原理的區(qū)別:

  • csr 時(shí)會(huì)從 vdom 創(chuàng)建 fiber,用于把渲染變成可打斷的,通過(guò)空閑調(diào)度來(lái)提高性能,而 ssr 時(shí)不會(huì),是 vdom 直接渲染的。
  • csr 時(shí)把 hooks 保存到了 fiber 節(jié)點(diǎn)上,ssr 時(shí)是直接放在了全局變量上,每個(gè)組件處理完就晴空。因?yàn)椴粫?huì)用第二次了。
  • csr 時(shí)會(huì)把 hook 的創(chuàng)建和更新分為 mount 和 update 兩個(gè)階段,而 ssr 因?yàn)橹粫?huì)處理一次,只有創(chuàng)建階段。

hooks 的實(shí)現(xiàn)原理其實(shí)不復(fù)雜,就是在某個(gè)上下文中存放一個(gè)鏈表,然后 hooks api 從鏈表不同的元素上訪問(wèn)對(duì)應(yīng)的數(shù)據(jù)來(lái)完成各自的邏輯。這個(gè)上下文可以是 vdom、fiber 甚至是全局變量。

不過(guò) hooks 這個(gè)思想還是挺火的,淘寶出的服務(wù)端框架 midway 就在引入了 hooks 的思想:

midway 如何實(shí)現(xiàn) hooks

midway 是一個(gè) Node.js 框架:

服務(wù)端框架自然就沒(méi)有 vdom、fiber 這種結(jié)構(gòu),不過(guò) hooks 的思想并不依賴這些,實(shí)現(xiàn) hooks 的 api 只需要在某個(gè)上下文放一個(gè)鏈表就行。

midway 就實(shí)現(xiàn)了類(lèi)似 react hooks 的 api:

具體它這個(gè) hook 鏈表存在哪我還沒(méi)看,不過(guò)我們已經(jīng)掌握 hooks 的實(shí)現(xiàn)原理了,只要有個(gè)上下文存放 hook 鏈表就行,在哪都可以。

總結(jié)

react hooks 是在 react fiber 架構(gòu)之后出現(xiàn)的特性,很多人誤以為 hooks 必須配合 fiber 才能實(shí)現(xiàn),我們分別看了 react、preact、react ssr、midway 中的 hooks 的實(shí)現(xiàn),發(fā)現(xiàn)并不是這樣的:

  • react 是把 vdom 轉(zhuǎn)成 fiber,然后把 hook 鏈表存放到了 fiber.memorizedState 屬性上,通過(guò) next 串聯(lián)
  • preact 沒(méi)有實(shí)現(xiàn) fiber,它是把 hook 鏈表放到了 vnode._component._hooks 屬性上,數(shù)組實(shí)現(xiàn)的,通過(guò)下標(biāo)訪問(wèn)
  • react ssr 時(shí)不需要 fiber,但是也沒(méi)有把 hook 鏈表掛到 vdom 上,而是直接放在了一個(gè)全局變量上,因?yàn)橹恍枰秩疽淮危秩就暌粋€(gè)組件就清空這個(gè)全局變量就行
  • midway 是一個(gè) Node.js 框架,它也實(shí)現(xiàn)了 hooks 類(lèi)似的 api,具體放在哪我們沒(méi)深入,但是只要有個(gè)上下文存放 hook 鏈表就行

所以,react hooks 必須依賴 fiber 才能實(shí)現(xiàn)么?

明顯不是,搭配 fiber、搭配 vdom、搭配全局變量,甚至任何一個(gè)上下文都可以。在框架中引入 hooks 的 api 并不難。

責(zé)任編輯:姜華 來(lái)源: 神光的編程秘籍
相關(guān)推薦

2020-10-28 09:12:48

React架構(gòu)Hooks

2022-02-11 13:44:56

fiber架構(gòu)React

2022-07-13 15:23:57

Vue fiberreact前端

2022-08-21 09:41:42

ReactVue3前端

2019-08-20 15:16:26

Reacthooks前端

2023-03-21 08:31:13

ReconcilerFiber架構(gòu)

2023-12-01 09:14:58

ReactFiber

2023-11-06 08:00:00

ReactJavaScript開(kāi)發(fā)

2024-06-04 14:17:26

2021-03-18 08:00:55

組件Hooks React

2022-03-31 17:54:29

ReactHooks前端

2020-09-19 17:46:20

React Hooks開(kāi)發(fā)函數(shù)

2019-03-13 10:10:26

React組件前端

2021-05-11 08:48:23

React Hooks前端

2023-05-08 07:52:29

JSXReactHooks

2022-02-10 19:15:18

React監(jiān)聽(tīng)系統(tǒng)模式

2022-03-22 13:39:10

框架react面試

2022-07-18 09:01:58

React函數(shù)組件Hooks

2020-08-10 06:31:01

React Hooks前端開(kāi)發(fā)

2022-03-16 22:24:50

ReactstateHooks
點(diǎn)贊
收藏

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