日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間: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)站托管維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、察哈爾右翼前網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

React 的版本為 18.2.0

ReactElement、fiber 和 Dom

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

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

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

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

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

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

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

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

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

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

function createFiberRoot(containerInfo, tag) {
// 生成 fiberRoot。containerInfo 是掛載根節(jié)點(diǎn)(比如 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)建一個(gè)了 fiberRoot,以及一個(gè) rootFiber。它們的關(guān)系如下:

一個(gè) fiberRoot 是 fiber 樹的根節(jié)點(diǎn)的維護(hù)者,是 fiberRootNode 實(shí)例,通過 current 確定要使用哪一棵 fiber 樹。

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

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

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

performUnitOfWork

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

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

workLoopConcurrent 的實(shí)現(xiàn):

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

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

function performUnitOfWork(unitOfWork) {
// 拿到當(dāng)前 fiber 節(jié)點(diǎn)的 “替身”
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 其實(shí)是對之前架構(gòu) “遞歸” 的模擬,這個(gè) beginWork 對應(yīng)著 “遞”。
  2. completeUnitOfWork:自下而上的合并階段。對應(yīng)遞歸的 “歸”。

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

beginWork

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

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

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

// 根據(jù)不同類型的組件,進(jìn)行不同的操作
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é)點(diǎn),workInProgress 是新節(jié)點(diǎn),屬于半成品,會在執(zhí)行過程中一點(diǎn)點(diǎn)填充內(nèi)容。

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

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

completeUnitOfWork

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

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

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

completeUnitOfWork 做的主要工作有:

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

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

結(jié)尾

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

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

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


新聞名稱:理解 React 的調(diào)和器 Reconciler
本文地址:http://www.5511xx.com/article/cdijcjj.html