React Fiber框架中的Render渲染階段——workLoop(performUnitOfWork【beginWork與completeWork】)

觸發渲染過程——renderRoot

renderRoot 是一個函數,用于觸發渲染工作。它通常會調用并遞歸地執行一系列的渲染任務,直到完成整個更新過程。這個過程包括執行 Fiber 樹中的 beginWork 和 completeWork,以及渲染新狀態或 DOM。

function renderRoot(root: FiberRootNode) {//雙緩存機制,將current復制一層給workInProgress//React 使用兩棵 Fiber 樹(current 和 workInProgress)來實現雙緩存const { current } = root; // 獲取當前的 Fiber 樹的根節點let workInProgress = current;// 啟動渲染任務(并發渲染模式下會啟動任務)workInProgress = performUnitOfWork(workInProgress);// 繼續調度工作單元while (workInProgress !== null) {workInProgress = performUnitOfWork(workInProgress);}
}

react源碼解析8.render階段
在這里插入圖片描述

renderRoot

React 的渲染過程可以分為多個階段,包括:更新(Reconciliation)、渲染(Rendering)、提交(Commit)等。
在這里插入圖片描述
在這里插入圖片描述

//更細節的
function renderRoot(root: FiberRootNode) {try {// 初始化prepareFreshStack(root);// 開始工作循環do{try{workLoop();break;} catch (e) {console.warn('workLoop發生錯誤', e);workInProgress = null;}while (true); // 獲取完成的工作單元const finishedWork = root.current.alternate;root.finishedWork = finishedWork; // 提交根節點的wip fiberNode樹,并處理flagscommitRoot(root);

prepareFreshStatck()

prepareFreshStatck()中的createWorkInProgress簡單理解就是上面將current復制一層給workInProgress, const { current } = root; // 獲取當前的 Fiber 樹的根節點 let workInProgress = current;,兩棵 Fiber 樹來實現雙緩存
在這里插入圖片描述
復制過后的雙緩存 數據結構
在這里插入圖片描述

workLoop()

function workLoop(){while(workInProgress !== null)performUnitOfWork(workInProgress);
}

performUnitOfWork(workInProgress) 【遞歸】

負責遞歸遍歷 Fiber 樹,并根據不同的 Fiber 類型執行相應的更新或渲染邏輯

function performUnitOfWork(fiber: FiberNode) {// 開始對當前Fiber節點進行工作// 這里的“遞”可能指的是遞歸處理子節點const next = beginWork(fiber); // 執行beginWork函數,返回下一個需要處理的Fiber節點// 更新當前Fiber節點的memoizedProps為pendingProps// 這通常意味著將傳入的props“確認”為當前節點的屬性fiber.memoizedProps = fiber.pendingProps;// 判斷下一個需要處理的節點是否為null// 如果為null,可能表示當前節點沒有子節點或子節點已經處理完畢if (next === null) {// 這里的“歸”可能指的是回溯到父節點,完成當前節點的工作completeUnitOfWork(fiber); // 執行completeUnitOfWork函數,完成當前Fiber節點的工作} else {// 如果還有下一個節點需要處理,則更新workInProgress指針// workInProgress通常指向當前正在處理的Fiber節點workInProgress = next; // 更新workInProgress為下一個需要處理的Fiber節點// 注意:這里通常會有一個遞歸調用performUnitOfWork(next),但在您提供的代碼片段中省略了}
}

遞歸結束狀態模型
在這里插入圖片描述

beginWork流程(遞)
  1. 建立節點的父子以及兄弟節點關聯關系
    child return sibling屬性
  2. 給fiber節點打上flag標記(當前節點的flag)

beginWork 主要發生在協調階段,它被調用來處理和更新 React 虛擬 DOM(Fiber 樹)。根據節點類型(HostRoot、FunctionComponent等)調用對應更新函數
1.初始化 Fiber 節點的工作:當 React 開始處理某個 Fiber 節點時,beginWork 會被調用。它會檢查該節點的當前狀態,并決定是否需要進行更新。
2.調度子節點的更新:如果當前節點有子節點,beginWork 會為這些子節點安排進一步的更新工作。
在執行過程中,beginWork 會遍歷 Fiber 樹,判斷是否需要更新(例如,檢查 props 或 state 是否發生了變化),然后決定是否繼續向下渲染(即繼續對子節點調用 beginWork)

export const beginWork = (wip: FiberNode): FiberNode | null => {// 根據Fiber節點的類型,執行相應的更新邏輯,并返回下一個需要處理的Fiber節點switch (wip.tag) {case 'HostRoot':return updateHostRoot(wip); // 處理根節點case 'HostComponent':return updateHostComponent(wip); // 處理宿主組件(如DOM元素)case 'HostText':return null; // 文本節點不需要進一步處理,直接返回nullcase 'FunctionComponent':return updateFunctionComponent(wip); // 處理函數組件default:console.warn('beginWork未實現的類型'); // 輸出警告信息break; // 注意:這里的break是多余的,因為return已經會退出函數// 但為了保持格式一致性和清晰性,我們暫時保留它return null; // 對于未實現的類型,返回null}

beginWork初次執行完, 此時內存狀態,wip和h1對應的fiber對象建立聯系,并且給h1 fiber打上flags標記
在這里插入圖片描述

updateHostRoot

更新隊列(processUpdateQueue【memorizedState=element元素】)、協調子元素(reconcileChildren)

在這里插入圖片描述

function updateHostRoot(wip: FiberNode): FiberNode | null {// 獲取當前工作單元(Fiber)的基態const baseState = wip.memoizedState as Element; // 假設memoizedState是Element類型// 獲取更新隊列,并斷言其類型為UpdateQueue<Element>const updateQueue = wip.updateQueue as UpdateQueue<Element>;// 從共享對象中取出待處理的更新,并清空待處理隊列const pending = updateQueue.shared.pending;updateQueue.shared.pending = null;// 使用processUpdateQueue函數處理待處理的更新,并獲取更新后的狀態//執行函數獲取element對象const { memoizedState } = processUpdateQueue(baseState, pending) as { memoizedState: Element };// 更新當前工作單元的基態為最新狀態wip.memoizedState = memoizedState;// 獲取更新后的子節點,這里假設memoizedState直接代表了子節點// 注意:這里的邏輯可能需要根據實際情況調整,因為memoizedState可能并不直接等于子節點const nextChildren = wip.memoizedState as Element[]; // 假設這里是Element數組,但需要根據實際情況確定// 調用reconcileChildren函數來協調(渲染)子節點// 注意:函數名可能是reconcileChildren的一個拼寫錯誤,通常應該是reconcileChildren或者類似的名稱,但這里按照您提供的名稱使用reconcileChildren(wip, nextChildren);// 返回當前工作單元的第一個子節點,以便后續的工作單元可以繼續處理// 注意:如果wip.child是null,則表示沒有子節點需要處理return wip.child;
}
processUpdateQueue

在這里插入圖片描述

export const processUpdateQueue = <state>(baseState: state,pendingUpdate: Update<state> | null
): { memoizedState: state } => {// 初始化結果對象,其memoizedState屬性設置為baseStateconst result: { memoizedState: state } = {memoizedState: baseState};// 檢查是否有待處理的更新if (pendingUpdate !== null) {const action = pendingUpdate.action;// 如果action是一個函數,則執行它并更新memoizedStateif (typeof action === 'function') {result.memoizedState = action(baseState);} else {// 如果action不是函數,則直接將其值賦給memoizedState// 注意:這里假設action的類型與state兼容result.memoizedState = action as state; // 需要類型斷言來確保TypeScript不會報錯}}// 返回結果對象return result;
};

在這里插入圖片描述
在這里插入圖片描述
** 注:Fiber對象數據結構 **

reconcileChildren(★★★)

reconcileChildren 主要處理組件的子樹,對于每一個子節點(即子 Fiber 節點)會執行以下操作:

  1. 子節點的類型判斷(會首先判斷每個子節點的類型【比如是 DOM 元素、函數組件還是類組件等】,然后根據不同的類型來決定如何處理)
  2. 節點的比較相同類型的節點/不同類型的節點/key 和索引
  3. 生成新的 Fiber 節點(為需要更新或新創建的子組件生成新的 Fiber 節點)
  4. 處理子樹的遞歸(beginWork中遞歸調用)(會遞歸地調用自己來處理子組件。如果某個子組件有子節點,React 會繼續對子節點進行協調,直到所有節點都被處理完)
    在這里插入圖片描述
    reconcileChildFibers|mountChildFibers
    創建子fiber的過程會進入reconcileChildren,該函數的作用是為workInProgress fiber節點生成它的child fiber即 workInProgress.child。然后繼續深度優先遍歷它的子節點執行相同的操作。mountChildFibers,reconcileChildFibers和mountChildFibers最終其實就是ChildReconciler傳遞不同的參數返回的函數,這個參數用來表示是否追蹤副作用.

在這里插入圖片描述

function ChildReconciler(shouldTrackSideEffects) {function placeChild(newFiber, lastPlacedIndex, newIndex) {newFiber.index = newIndex;if (!shouldTrackSideEffects) {//是否追蹤副作用// Noop.return lastPlacedIndex;}var current = newFiber.alternate;if (current !== null) {var oldIndex = current.index;if (oldIndex < lastPlacedIndex) {// This is a move.newFiber.flags = Placement;return lastPlacedIndex;} else {// This item can stay in place.return oldIndex;}} else {// This is an insertion.newFiber.flags = Placement;return lastPlacedIndex;}}
}

在這里插入圖片描述

const App:any=function (){return(<h1><h2><h3>3333</h3></h2></h1>)
}

初次被調用執行, 此時內存狀態,wip和h1對應的fiber對象建立聯系,并且給h1 fiber打上flags標記
在這里插入圖片描述
遞歸,直至next指向為null
在這里插入圖片描述

completeWork流程(歸)

主要執行任務:
1.創建真實dom節點,但是仍在內存中,未渲染到頁面
2.處理flag與subtreeFlags標記子樹標識,用“|”運算處理)
3.建立真實DOM關系,將子元素插入父元素中

function completeWork(current, workInProgress) {switch (workInProgress.tag) {case 'HostComponent': {// 如果是普通的 DOM 節點if (!workInProgress.stateNode) {// 如果沒有對應的 DOM 實例,創建一個新的const domElement = document.createElement(workInProgress.type);// 為 DOM 元素添加屬性const props = workInProgress.pendingProps;for (const key in props) {if (key === 'children') {// 如果是文本內容,直接設置if (typeof props[key] === 'string' || typeof props[key] === 'number') {domElement.textContent = props[key];}} else if (key.startsWith('on')) {// 添加事件監聽器(如 onClick)const eventType = key.toLowerCase().substring(2);domElement.addEventListener(eventType, props[key]);} else {// 設置其他屬性domElement.setAttribute(key, props[key]);}}// 將 DOM 實例存儲在 stateNode 中workInProgress.stateNode = domElement;}return null;}case 'FunctionComponent':case 'ClassComponent': {// 函數組件和類組件在 completeWork 中通常不需要特殊處理return null;}default:return null;}
}

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/65915.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/65915.shtml
英文地址,請注明出處:http://en.pswp.cn/web/65915.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【優先算法】思還故里閭,欲歸道無因 - 前綴和

本篇博客給大家帶來的是前綴和算法的知識點, 也是一樣通過OJ題理解,掌握,應用該算法. &#x1f40e;文章專欄: 算法 &#x1f680;若有問題 評論區見 ? 歡迎大家點贊 評論 收藏 分享 如果你不知道分享給誰,那就分享給薯條. 你們的支持是我不斷創作的動力 . 王子,公主請閱&…

億道三防丨三防筆記本是什么意思?和普通筆記本的優勢在哪里?

三防筆記本是什么意思&#xff1f;和普通筆記本的優勢在哪里&#xff1f; 在現代社會中&#xff0c;筆記本電腦已經成為人們工作和生活中不可或缺的一部分。然而&#xff0c;在一些特殊行業或環境中&#xff0c;普通筆記本電腦由于其脆弱性和對環境條件的敏感性&#xff0c;往…

SOME/IP 協議詳解——服務發現

文章目錄 1. Introduction &#xff08;引言&#xff09;2. SOME/IP Service Discovery (SOME/IP-SD)2.1 General&#xff08;概述)2.2 SOME/IP-SD Message Format2.2.1 通用要求2.2.2 SOME/IP-SD Header2.2.3 Entry Format2.2.4 Options Format2.2.4.1 配置選項&#xff08;Co…

MATLAB語言的函數實現

MATLAB語言中的函數實現詳解 引言 MATLAB&#xff08;矩陣實驗室&#xff09;是一種高級語言和互動環境&#xff0c;廣泛應用于數值計算、數據分析、可視化以及工程與科學計算等多個領域。MATLAB的強大之處在于其豐富的函數庫以及用戶自定義函數的能力。本文將深入探討MATLAB…

Go語言之路————go環境的初始化

Go語言之路————go環境的初始化 前言一、Go的安裝二、環境配置三、初始化一個新項目四、常用的一些指令 前言 我是一名多年Java開發人員&#xff0c;因為工作需要現在要學習go語言&#xff0c;Go語言之路是一個系列&#xff0c;記錄著我從0開始接觸Go&#xff0c;到后面能正…

鼠標過濾驅動

文章目錄 概述代碼參考資料 概述 其編寫過程大體與鍵盤過濾驅動相似&#xff0c;只需要切換一下附加的目標設備以及創建的設備類型等。但在該操作后依然無法捕獲到Vmware創建的win7操作系統的鼠標irp信息&#xff0c;于是通過在獲取鼠標驅動&#xff0c;遍歷其所有的設備進而附…

鴻蒙UI開發——基于onTouch事件實現表情選擇膠囊

1、背 景 有朋友留言說&#xff0c;抖音APP中&#xff0c;長按評論按鈕觸發的快捷表情選擇膠囊動畫比較好&#xff08;效果如下圖&#xff09;&#xff0c;希望使用鴻蒙ArkTs也實現一個類似的。 本文在鴻蒙ArkTs下也實現一個類似的效果&#xff0c;如下&#xff1a; 首先&…

Node.js——http 模塊(二)

個人簡介 &#x1f440;個人主頁&#xff1a; 前端雜貨鋪 &#x1f64b;?♂?學習方向&#xff1a; 主攻前端方向&#xff0c;正逐漸往全干發展 &#x1f4c3;個人狀態&#xff1a; 研發工程師&#xff0c;現效力于中國工業軟件事業 &#x1f680;人生格言&#xff1a; 積跬步…

研華 PCI-1751 驅動更新導LabVIEW致程序異常

問題描述&#xff1a; 某 LabVIEW 程序長期運行正常&#xff0c;但在使用研華 PCI-1751 數據采集卡運行一段時間后&#xff0c;程序開始出現不正常的行為。具體過程如下&#xff1a; 初始問題&#xff1a; 更換新的 PCI-1751 板卡后&#xff0c;驅動程序被更新&#xff0c;但程…

接上篇基于Alertmanager 配置釘釘告警

Alertmanager 是一個用于處理和管理 Prometheus 警報的開源工具。它負責接收來自 Prometheus 服務器的警報&#xff0c;進行去重、分組、靜默、抑制等操作&#xff0c;并通過電子郵件、PagerDuty、Slack 等多種渠道發送通知。 主要功能 去重&#xff1a;合并相同或相似的警報&…

網絡原理(三)—— 傳輸層 之 UDP 和 TCP協議

傳輸層 在傳輸層兩大關鍵的協議就是UDP和TCP協議了&#xff0c;除此之外&#xff0c;還有別的傳輸層協議&#xff0c;本文章將介紹UDP和TCP協議&#xff0c;重點介紹TCP協議。 首先回顧TCP和UDP 的特點&#xff1a; UDP&#xff1a;不可靠傳輸&#xff0c;面向數據包&#xf…

針對服務器磁盤爆滿,MySql數據庫始終無法啟動,怎么解決

&#xff08;點擊即可進入聊天助手&#xff09; 很多站長在運營網站的過程當中都會遇到一個問題,就是網站突然無法打開,數據一直無法啟動 無論是強制重啟還是,刪除網站內的所有應用,數據庫一直無法啟動 這個時候,就需要常見的運維手段了,需要對服務器后臺各個資源,進行逐一排查…

高性能現代PHP全棧框架 Spiral

概述 Spiral Framework 誕生于現實世界的軟件開發項目是一個現代 PHP 框架&#xff0c;旨在為更快、更清潔、更卓越的軟件開發提供動力。 特性 高性能 由于其設計以及復雜精密的應用服務器&#xff0c;Spiral Framework框架在不影響代碼質量以及與常用庫的兼容性的情況下&a…

【面試題】Spring/SpringBoot部分[2025/1/6 ~ 2025/1/12]

Spring/SpringBoot部分[2025/1/6 ~ 2025/1/12] 1. 說說 Spring 啟動過程&#xff1f;2. 說說 Springboot 的啟動流程&#xff1f;3. 你了解的 Spring 都用到哪些設計模式&#xff1f;4. Spring 有哪幾種事務傳播行為?5. SpringBoot 是如何實現自動配置的&#xff1f;6. Spring…

【機器學習:十八、更高級的神經網絡概念】

1. 梯度下降法的改進&#xff1a;Adam算法 1.1 Adam算法簡介 Adam&#xff08;Adaptive Moment Estimation&#xff09;是一種優化算法&#xff0c;結合了動量梯度下降和 RMSProp 的優點&#xff0c;在處理稀疏梯度和高維空間優化時表現尤為出色。其核心在于動態調整每個參數…

計算機網絡之---VPN與隧道協議

VPN與隧道協議 VPN&#xff08;虛擬專用網絡&#xff09;和隧道協議是現代網絡安全技術的重要組成部分&#xff0c;它們主要用于在不安全的公共網絡&#xff08;如互聯網&#xff09;上建立一個安全的私密網絡連接。VPN通過加密通信和認證機制&#xff0c;確保數據的隱私性和完…

【STM32-學習筆記-6-】DMA

文章目錄 DMAⅠ、DMA框圖Ⅱ、DMA基本結構Ⅲ、不同外設的DMA請求Ⅳ、DMA函數Ⅴ、DMA_InitTypeDef結構體參數①、DMA_PeripheralBaseAddr②、DMA_PeripheralDataSize③、DMA_PeripheralInc④、DMA_MemoryBaseAddr⑤、DMA_MemoryDataSize⑥、DMA_MemoryInc⑦、DMA_DIR⑧、DMA_Buff…

SQL Server中可以通過擴展事件來自動抓取阻塞

在SQL Server中可以通過擴展事件來自動抓取阻塞&#xff0c;以下是詳細流程&#xff1a; 開啟阻塞跟蹤配置&#xff1a; ? 執行以下SQL語句來啟用相關配置&#xff1a; EXEC sp_configureshow advanced options, 1; RECONFIGURE; EXEC sp_configure blocked process thresh…

DNS解析域名簡記

域名通常是由: 權威域名.頂級域名.根域名組成的。 從左往右&#xff0c;級別依次升高&#xff0c;這和外國人從小范圍到大范圍的說話習慣相關。&#xff08;我們自己是更習慣先說大范圍再說小范圍&#xff0c;如XX省XX市XX區XX路&#xff09; DNS解析域名時&#xff0c;會先查…

【爬蟲】單個網站鏈接爬取文獻數據:標題、摘要、作者等信息

源碼鏈接&#xff1a; https://github.com/Niceeggplant/Single—Site-Crawler.git 一、項目概述 從指定網頁中提取文章關鍵信息的工具。通過輸入文章的 URL&#xff0c;程序將自動抓取網頁內容 二、技術選型與原理 requests 庫&#xff1a;這是 Python 中用于發送 HTTP 請求…