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.mzph.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…

Go语言之路————go环境的初始化

Go语言之路————go环境的初始化 前言一、Go的安装二、环境配置三、初始化一个新项目四、常用的一些指令 前言 我是一名多年Java开发人员&#xff0c;因为工作需要现在要学习go语言&#xff0c;Go语言之路是一个系列&#xff0c;记录着我从0开始接触Go&#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…

【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…

【爬虫】单个网站链接爬取文献数据:标题、摘要、作者等信息

源码链接&#xff1a; https://github.com/Niceeggplant/Single—Site-Crawler.git 一、项目概述 从指定网页中提取文章关键信息的工具。通过输入文章的 URL&#xff0c;程序将自动抓取网页内容 二、技术选型与原理 requests 库&#xff1a;这是 Python 中用于发送 HTTP 请求…

关于扫描模型 拓扑 和 传递贴图工作流笔记

关于MAYA拓扑和传递贴图的操作笔记 一、拓扑低模: 1、拓扑工作区位置: 1、准备出 目标 高模。 (高模的状态如上 ↑ )。 2、打开顶点吸附,和建模工具区,选择四边形绘制. 2、拓扑快捷键使…

解决无法远程管理Windows Server服务器核心安装

问题 有时&#xff0c;人们会为了节省运算资源&#xff0c;例如运行Hyper-V虚拟机&#xff0c;而选择Windows Server核心安装&#xff0c;即无图形化界面。这时&#xff0c;我们就只能通过Powershell命令对其进行操控&#xff0c;或为了获得图形化界面而使用远程服务器管理工具…

【计算机网络】lab7 TCP协议

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;计算机网络_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 实验目的…

JavaRestClient 客户端初始化+索引库操作

1. 介绍 ES官方提供了各种不同语言的客户端&#xff0c;用来操作ES。这些客户端的本质就是组装DSL语句&#xff0c;通过http请求发送给ES。 Elasticsearch目前最新版本是8.0&#xff0c;其java客户端有很大变化。不过大多数企业使用的还是8以下版本 2. 客户端初始化 在elastic…

【JVM-2.2】使用JConsole监控和管理Java应用程序:从入门到精通

在Java应用程序的开发和运维过程中&#xff0c;监控和管理应用程序的性能和资源使用情况是非常重要的。JConsole是Java Development Kit&#xff08;JDK&#xff09;自带的一款图形化监控工具&#xff0c;它可以帮助开发者实时监控Java应用程序的内存、线程、类加载以及垃圾回收…

基于html5实现音乐录音播放动画源码

源码介绍 基于html5实现音乐录音播放动画源码是一款类似Shazam的UI&#xff0c;点击按钮后&#xff0c;会变成为一个监听按钮。旁边会有音符飞入这个监听按钮&#xff0c;最后转换成一个音乐播放器。 效果预览 源码获取 基于html5实现音乐录音播放动画源码