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.rhkb.cn/news/968.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32裸机开发转FreeRTOS教程

目录 1. 简介2. RTOS设置&#xff08;1&#xff09;分配内存&#xff08;2&#xff09;查看任务剩余空间&#xff08;3&#xff09;使用osDelay 3. 队列的使用&#xff08;1&#xff09;创建队列&#xff08;1&#xff09;直接传值和指针传值&#xff08;2&#xff09;发送/接收…

Elasticsearch快速入门

Elasticsearch是由elastic公司开发的一套搜索引擎技术&#xff0c;它是elastic技术栈中的一部分,提供核心的数据存储、搜索、分析功能 elasticsearch之所以有如此高性能的搜索表现&#xff0c;正是得益于底层的倒排索引技术。那么什么是倒排索引呢&#xff1f; Elasticsearch…

新版AndroidStudio通过系统快捷创建带BottomNavigationView的项目踩坑记录

选择上面这个玩意创建的项目 坑点1 &#xff1a;配置的写法和不一样了 镜像的写法&#xff1a; 新的settings.gradle.kts中配置镜像的代码&#xff1a; pluginManagement {repositories {mavenCentral()google {content {includeGroupByRegex("com\\.android.*")…

Unity 自定义批量打包工具

打包配置项 using UnityEngine; using System.Collections.Generic;namespace MYTOOL.Build {/// <summary>/// 批量打包配置文件/// </summary>[CreateAssetMenu]public class BatchBuildProfile : ScriptableObject{public List<BuildTask> tasks new Li…

【JVM-2.3】深入解析JVisualVM:Java性能监控与调优利器

在Java应用的开发和运维过程中&#xff0c;性能监控与调优是不可或缺的环节。无论是排查内存泄漏、分析CPU瓶颈&#xff0c;还是优化线程使用&#xff0c;开发者都需要借助一些强大的工具来辅助诊断。JVisualVM 正是这样一款由Oracle提供的免费工具&#xff0c;它集成了多种性能…

基于大语言模型的组合优化

摘要&#xff1a;组合优化&#xff08;Combinatorial Optimization, CO&#xff09;对于提高工程应用的效率和性能至关重要。随着问题规模的增大和依赖关系的复杂化&#xff0c;找到最优解变得极具挑战性。在处理现实世界的工程问题时&#xff0c;基于纯数学推理的算法存在局限…

计算机网络 (40)域名系统DNS

前言 计算机网络域名系统DNS&#xff08;Domain Name System&#xff09;是互联网的基础技术之一&#xff0c;它负责将人类可读的域名转换为计算机用来通信的数字IP地址。 一、基本概念 DNS的主要目的是将域名解析或翻译为IP地址&#xff0c;使得用户可以通过简单易记的域名来访…

说一说mongodb组合索引的匹配规则

一、背景 有一张1000多万条记录的大表&#xff0c;需要做归档至历史表&#xff0c;出现了大量慢查询。 查询条件是 "classroomId": {$in: ["xxx", "xxx", ..... "xxx","xxx", "xxx" ] }耗时近5秒&#xff0c;且…

C# OpenCV机器视觉:转速测量

在一个看似平常却又暗藏神秘能量的日子里&#xff0c;阿杰正在他那充满科技感的实验室里&#xff0c;对着一堆奇奇怪怪的仪器发呆。突然&#xff0c;手机铃声如一道凌厉的剑气划破寂静&#xff0c;原来是工厂的赵厂长打来的紧急电话&#xff1a;“阿杰啊&#xff0c;咱们工厂新…

【RedisStack】Linux安装指南

【RedisStack】Linux安装指南.md 前言下载解压创建启动文件设置密码把密码设置到环境变量启动/停止相关命令测试&验证官网资料参考资料 前言 Redis Stack是使用Redis的最佳起点。我们将我们必须提供的最好的技术捆绑在一起&#xff0c;形成一个易于使用的软件包。Redis St…

2025-微服务—SpringCloud-1~3

2025-微服务—SpringCloud 第一章、从Boot和Cloud版本选型开始说起1、Springboot版本2、Springcloud版本3、Springcloud Alibaba4、本次讲解定稿版 第二章 关于Cloud各种组件的停更/升级/替换1、微服务介绍2、SpringCloud是什么&#xff1f;能干吗&#xff1f;产生背景&#xf…

深度学习-卷积神经网络反向传播梯度公式推导

这篇文章非常棒&#xff0c;单样本单通道的反向传播梯度公式推导我都理解了。为了防止找不到原网页&#xff0c;所以特复制于此 参考&#xff1a; https://zhuanlan.zhihu.com/p/640697443

MongoDB实践

MongoDB 是什么&#xff1f;— MongoDB 手册 v8.0 现在有一个名为city的集合&#xff0c;里面的结构如下图 一、增删改查操作 1.查询find db.getCollection("city").find({})db.city.find({})db.city.find({city:"广州" });db.city.find({city_id:17,ci…

mycat介绍与操作步骤

文章目录 1.分库分表2.mycat 入门2.1 概述2.2 案例&#xff1a;水平分表1&#xff09;准备工作2&#xff09;配置3&#xff09;启动并测试 3.mycat 配置详解3.1 schema.xml3.2 rule.xml3.3 server.xml 4.mycat 分片&#xff1a;垂直拆分1&#xff09;准备工作2&#xff09;配置…

苹果手机(IOS系统)出现安全延迟进行中如何关闭?

苹果手机&#xff08;IOS系统&#xff09;出现安全延迟进行中如何关闭&#xff1f; 一、设置二、隐私与安全性三、失窃设备保护关闭 一、设置 二、隐私与安全性 三、失窃设备保护关闭

线形回归与小批量梯度下降实例

1、准备数据集 import numpy as np import matplotlib.pyplot as pltfrom torch.utils.data import DataLoader from torch.utils.data import TensorDataset######################################################################### #################准备若干个随机的x和…

【Unity3D日常开发】Unity3D中打开Window文件对话框打开文件(PC版)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 这篇文章继续讲如何使用Unity3D打开Window文…

iOS 逆向学习 - Inter-Process Communication:进程间通信

iOS 逆向学习 - Inter-Process Communication&#xff1a;进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…

零基础 监控数据可视化 Spring Boot 2.x(Actuator + Prometheus + Grafana手把手) (上)

一、安装Prometheus Releases prometheus/prometheus GitHubhttps://github.com/prometheus/prometheus/releases 或 https://prometheus.io/download/https://prometheus.io/download/ 1. 下载适用于 Windows 的二进制文件&#xff1a; 找到最新版本的发布页面&#xf…

【API】免费调用Qwen-vl2对图像打标

首次调用通义千问API_大模型服务平台百炼(Model Studio)-阿里云帮助中心https://help.aliyun.com/zh/model-studio/getting-started/first-api-call-to-qwen?spma2c4g.11186623.help-menu-2400256.d_0_1_0.8c693048HxtUzZ&scm20140722.H_2840915._.OR_help-T_cn~zh-V_1 一…