日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
理解 React 的調(diào)和器 Reconciler

大家好,我是前端西瓜哥。今天來學(xué)習(xí) React 中的調(diào)和器 Reconciler。

目前成都創(chuàng)新互聯(lián)已為1000多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站托管維護、企業(yè)網(wǎng)站設(shè)計、察哈爾右翼前網(wǎng)站維護等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

React 的版本為 18.2.0

ReactElement、fiber 和 Dom

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

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

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

fiber 會根據(jù) ReactElement 構(gòu)建成一棵樹。當(dāng)更新時,組件會調(diào)用 render 方法生成新的 ReactElement,然后我們再構(gòu)建一個新的 Fiber 樹,和舊樹對比。

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

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

一個 App 組件的 fiber 樹結(jié)構(gòu):

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

構(gòu)建 Fiber 樹的過程

在調(diào)用 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);
// 互相關(guān)聯(lián)
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;

return root;
}

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

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

每調(diào)用 createRoot 都會構(gòu)建新的 fiber 樹,并生成一個新的 fiberRoot 去指向它。

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

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

performUnitOfWork

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

這個函數(shù)會不斷地處理以 fiber 為單位的任務(wù)。

workLoopConcurrent 的實現(xiàn):

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

看看 performUnitOfWork 的核心實現(xiàn):

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

performUnitOfWork 由兩部分組成:

  1. beginWork:自上而下的調(diào)和,主要在構(gòu)建 fiber。fiber 其實是對之前架構(gòu) “遞歸” 的模擬,這個 beginWork 對應(yīng)著 “遞”。
  2. completeUnitOfWork:自下而上的合并階段。對應(yīng)遞歸的 “歸”。

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

beginWork

performUnitOfWork 中,先調(diào)用 beginWork。

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

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

// 根據(jù)不同類型的組件,進行不同的操作
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í)行過程中一點點填充內(nèi)容。

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

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

completeUnitOfWork

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

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

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

completeUnitOfWork 做的主要工作有:

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

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

結(jié)尾

調(diào)和階段,主要分為 beginWork 和 completeUnitOfWork 兩部分。

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

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


本文名稱:理解 React 的調(diào)和器 Reconciler
URL鏈接:http://www.dlmjj.cn/article/cdijcjj.html