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

理解 React 的調和器 Reconciler

開發(fā) 前端
ReactElement 就是 React.createElement() 方法的返回結果,一種 映射真實 DOM 層級關系的對象,但里面可以帶上組件元素。通常我們會用 JSX 去寫。

大家好,我是前端西瓜哥。今天來學習 React 中的調和器 Reconciler。

React 的版本為 18.2.0

ReactElement、fiber 和 Dom

ReactElement 就是 React.createElement() 方法的返回結果,一種 映射真實 DOM 層級關系的對象,但里面可以帶上組件元素。通常我們會用 JSX 去寫。

類組件的 render 方法的返回值和函數組件的返回值都是 ReactElement。

fiber 是一個節(jié)點,是 React Fiber 時間分片架構中的一個節(jié)點。fiber 是 ReactElement 和真實 DOM 的橋梁。

fiber 會根據 ReactElement 構建成一棵樹。當更新時,組件會調用 render 方法生成新的 ReactElement,然后我們再構建一個新的 Fiber 樹,和舊樹對比。

fiber 樹下的 fiber 節(jié)點通過下面三個字段進行關聯:

  • return:父 fiber。
  • child:子 fiber 的第一個。
  • sibling :下一個兄弟節(jié)點。

一個 App 組件的 fiber 樹結構:

圖片

App 的 child 是會指向它創(chuàng)建的 element 對應 fiber 的根節(jié)點。

構建 Fiber 樹的過程

在調用 createRoot(并發(fā)模式)或者 ReactDOM.render(同步模式)時,會執(zhí)行 createFiberRoot 方法。

function createFiberRoot(containerInfo, tag) {
// 生成 fiberRoot。containerInfo 是掛載根節(jié)點(比如 div#root)
const root = new FiberRootNode(containerInfo, tag);
// 生成 rootFiber
const uninitializedFiber = createHostRootFiber(tag);
// 互相關聯
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;

return root;
}

createFiberRoot 創(chuàng)建一個了 fiberRoot,以及一個 rootFiber。它們的關系如下:

圖片

一個 fiberRoot 是 fiber 樹的根節(jié)點的維護者,是 fiberRootNode 實例,通過 current 確定要使用哪一棵 fiber 樹。

每調用 createRoot 都會構建新的 fiber 樹,并生成一個新的 fiberRoot 去指向它。

rootFiber 是一顆 fiber 樹的根節(jié)點,也屬于是 fiber 節(jié)點。rootFiber 通過屬性 stateNode 訪問到 fiberRoot。注意不是 return,因為 fiberRoot 的結構完全不一樣,不是 fiber 節(jié)點。

creatRoot 方法返回的是個對象,它的 _internalRoot 屬性指向的是這個 fiberRoot。

performUnitOfWork

在 workLoopSync 或 workLoopConcurrent 中,是會不斷地調用  performUnitOfWork(workInProgress) 的。

這個函數會不斷地處理以 fiber 為單位的任務。

workLoopConcurrent 的實現:

function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}

看看 performUnitOfWork 的核心實現:

function performUnitOfWork(unitOfWork) {
// 拿到當前 fiber 節(jié)點的 “替身”
var current = unitOfWork.alternate;
var next = beginWork(current, unitOfWork, subtreeRenderLanes); // 遞
if (next === null) {
completeUnitOfWork(unitOfWork); // 歸
} else {
workInProgress = next;
}
}

performUnitOfWork 由兩部分組成:

  1. beginWork:自上而下的調和,主要在構建 fiber。fiber 其實是對之前架構 “遞歸” 的模擬,這個 beginWork 對應著 “遞”。
  2. completeUnitOfWork:自下而上的合并階段。對應遞歸的 “歸”。

還是這個 fiber 樹的圖,這里的粉色的 1、2、4 表示的是 beginWork,3、5 則代表 completeUnitOfWork。

圖片

beginWork

performUnitOfWork 中,先調用 beginWork。

beginWork 的作用是,自上而下根據組件進行組件實例化,根據新的 element 構建 fiber,給舊的 fiber 打上 effectTag。

function beginWork(current, workInProgress, renderLanes) {
if (current !== null) {
const oldProps = current.memoizedProps;
const newProps = workInProgress.pendingProps;
}

// 根據不同類型的組件,進行不同的操作
switch (workInProgress.tag) {
// ...

case ClassComponent: {
const Component = workInProgress.type;
// 未處理的新 props 對象
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
// 更新組件
return updateClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}

// ...
}
}

current 是舊節(jié)點,workInProgress 是新節(jié)點,屬于半成品,會在執(zhí)行過程中一點點填充內容。

beginWork 會進行深度優(yōu)先遍歷,生成的新節(jié)點 workInProcess 會 tag 屬性進入不同的 update 邏輯分支,比如常見的 updateHostRoot、updateClassComponent、updateFunctionComponent 等。

  1. 會做組件實例化,拿到新 ReactElement,然后調用 reconcileChildFibers 方法進行 新舊節(jié)點 diff,深度遞歸構建子 fiber,形成子 fiber 樹,并把一些數據持久化掛載到 fiber 上。
  2. 在這個過程中,會給 workInProcess 打標記。具體是在 fiber.flags 上標記  Placement(插入)、Update(更新)等 flags。比如在同層級進行對比,發(fā)現舊節(jié)點有需要刪除的 fiber,這些 fiber 會放到新父 fiber 的 deletions 數組中,并加上 ChildDetetion 標簽。
  3. 這期間穿插調用了一些生命周期函數(比如 shouldComponentUpdate),都是是在新舊節(jié)點對比前,準確來說是調用 render 拿到 ReactElement 的時機之前。

completeUnitOfWork

performUnitOfWork 中,調用完 beginWork 后,會返回一個 next。這個 next 就是下一個要處理的 fiber,是 unitOfWork 的子 fiber。

這個 next 會賦值給 workInProgress,然后 workLoopConcurrent 的循環(huán)會 處理這個新的 workInProcess。

但當 next 為 null,就表示找不到下一個 fiber 了,深度的 “遞” 到底了,就要 調用 completeUnitOfWork,進行 “歸” 的收尾工作。

completeUnitOfWork 做的主要工作有:

  1. 根據 fiber 的類型不同,進行不同的處理。對于原生組件類型(比如 div、span)的掛載階段,會用 createInstance 創(chuàng)建 一個真實 DOM,這個 DOM 下還沒有子節(jié)點,然后還會將其下所有子 fiber 對應的真實 DOM 加到這個 DOM 下,然后賦值給 fiber.stateNode,此時這個 DOM 元素目前什么屬性都沒有。
  2. 根據 props,調用 setInitialProperties 方法綁定合成事件,以及設置 DOM 屬性。

React 16 時會生成一個 effectList 來記錄需要更新的節(jié)點,防止不必要的遍歷整棵樹。但 React 17 后被移除掉了,改成從 rootFiber 開始從上往下遍歷。

結尾

調和階段,主要分為 beginWork 和 completeUnitOfWork 兩部分。

beginWork 自上而下,進行新舊節(jié)點對比,構造子 fiber,并打上 flag(插入、更新、刪除),會執(zhí)行 render(生成新 ReactElement) 之前的生命周期函數。對應以前 stack reconciler 架構中遞歸的 “遞”。

completeUnitOfWork 自下而上,如果是插入,則構建真實 DOM 節(jié)點放到 fiber.stateNode 下,接著是處理 props,將屬性添加到 DOM 上。

責任編輯:姜華 來源: 前端西瓜哥
相關推薦

2023-03-28 07:59:57

ReactReconciler

2022-07-06 08:30:36

vuereactvdom

2021-11-26 08:33:51

React組件前端

2024-03-22 07:48:51

ReactScheduler底層調度器

2016-10-26 20:49:24

ReactJavascript前端

2021-05-11 08:48:23

React Hooks前端

2022-12-20 08:22:42

CommitMuation

2022-12-23 08:34:30

HookReact

2024-04-19 12:50:58

人工智能OpenAI

2022-05-04 10:38:58

React閉包組件

2021-06-30 07:19:36

React事件機制

2022-12-07 11:21:30

Reactdiff

2023-11-16 07:43:26

Next.jsReact

2022-05-05 08:31:48

useRefuseEffecthook

2024-01-16 08:43:51

React底層機制Hook

2022-08-21 09:41:42

ReactVue3前端

2021-07-07 08:36:45

React應用場景

2024-04-10 10:09:07

2020-04-27 09:40:13

Reacthooks前端

2023-11-29 09:00:55

ReactuseMemo
點贊
收藏

51CTO技術棧公眾號