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

news2025/3/3 18:41:48

触发渲染过程——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树,并处理flags
  commitRoot(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; // 文本节点不需要进一步处理,直接返回null
    case '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属性设置为baseState
  const result: { memoizedState: state } = {
    memoizedState: baseState
  };
 
  // 检查是否有待处理的更新
  if (pendingUpdate !== null) {
    const action = pendingUpdate.action;
 
    // 如果action是一个函数,则执行它并更新memoizedState
    if (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.coloradmin.cn/o/2275944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32F1学习——ADC模数转换器

一、ADC模数转换器 ADC的全称 Analog-Digital Converter 模拟-数字转换器&#xff0c;他可以用来将引脚上连续变换的模拟电压转换为内存中存储的数字变量。 ADC有两个重要指标&#xff0c;分辨率和频率。 STM32的ADC是 12位 逐次逼近型&#xff0c;1us转换时间&#xff0c;也就…

[每周一更]-(第131期):Go并发协程总结篇

Go语言的并发是通过协程&#xff08;goroutine&#xff09;实现的。Go协程是轻量级的线程&#xff0c;允许多个任务同时执行&#xff0c;且Go运行时会高效地管理它们。在Go中使用并发协程的方式非常简便&#xff0c;也很强大。以下是一些关于Go协程的基础用法和并发控制方法&am…

Ecdsa密钥在线生成工具

具体前往&#xff1a;ECC公钥私钥对在线生成器

llama.cpp 模型可视化工具 GGUF Visualizer

llama.cpp 模型可视化工具 GGUF Visualizer 1. GGUF Visualizer for VS Code (gguf-viz)1.1. Features1.2. Extension Settings References GGUF Visualizer https://marketplace.visualstudio.com/items?itemNameAgainstEntropy.gguf-viz 1. GGUF Visualizer for VS Code (g…

【DAPM杂谈之三】DAPM的初始化流程

本文主要分析DAPM的设计与实现 内核的版本是&#xff1a;linux-5.15.164&#xff0c;下载链接&#xff1a;Linux内核下载 主要讲解有关于DAPM相关的知识&#xff0c;会给出一些例程并分析内核如何去实现的 /**************************************************************…

HarmonyOS:@LocalBuilder装饰器: 维持组件父子关系

一、前言 当开发者使用Builder做引用数据传递时&#xff0c;会考虑组件的父子关系&#xff0c;使用了bind(this)之后&#xff0c;组件的父子关系和状态管理的父子关系并不一致。为了解决组件的父子关系和状态管理的父子关系保持一致的问题&#xff0c;引入LocalBuilder装饰器。…

Pytorch导出onnx模型并在C++环境中调用(含python和C++工程)

Pytorch导出onnx模型并在C环境中调用&#xff08;含python和C工程&#xff09; 工程下载链接&#xff1a;Pytorch导出onnx模型并在C环境中调用&#xff08;python和C工程&#xff09; 机器学习多层感知机MLP的Pytorch实现-以表格数据为例-含数据集和PyCharm工程中简单介绍了在…

git打补丁

1、应用场景 跨仓库升级 开发项目B使用的是开源项目A。开源项目A发现漏洞&#xff0c;作者进行了修复&#xff0c;我们可以通过使用git补丁的方式&#xff0c;将作者修改的内容复制到我 们的项目B中。 2、TortoiseGit方式 源仓库 格式化补丁 根据提交数量&#xff0c;生成…

计算机网络 (34)可靠传输的工作原理

前言 计算机网络可靠传输的工作原理主要依赖于一系列协议和机制&#xff0c;以确保数据在传输过程中能够准确无误地到达目的地。 一、基本概念 可靠传输指的是数据链路层的发送端发送什么&#xff0c;在接收端就收到什么&#xff0c;即保证数据的完整性、正确性和顺序性。由于网…

基于ADAS 与关键点特征金字塔网络融合的3D LiDAR目标检测原理与算法实现

一、概述 3D LiDAR目标检测是一种在三维空间中识别和定位感兴趣目标的技术。在自动驾驶系统和先进的空间分析中&#xff0c;目标检测方法的不断演进至关重要。3D LiDAR目标检测作为一种变革性的技术&#xff0c;在环境感知方面提供了前所未有的准确性和深度信息. 在这里&…

Vue3初学之常用的指令

v-bind&#xff1a;动态绑定属性 v-bind 用于动态绑定一个或多个属性&#xff0c;或一个组件 prop 到表达式的值。 v-model&#xff1a;双向数据绑定 见上篇 https://editor.csdn.net/md/?articleId145022994 v-if、v-else-if、v-else&#xff1a;条件渲染 v-show&…

docker中jenkins流水线式部署GitLab中springboot项目

本质就是将java项目拉取下来&#xff0c;并自动打包成docker镜像&#xff0c;运行 首先启动一个docker的jenkins 如果没有镜像使用我的镜像 通过网盘分享的文件&#xff1a;jenkins.tar 链接: https://pan.baidu.com/s/1VJOMf6RSIQbvW_V1zFD7eQ?pwd6666 提取码: 6666 放入服…

在ubuntu下对NFS做性能测试

安装NFS 首先&#xff0c;安装服务 sudo apt update sudo apt install nfs-kernel-server然后创建共享文件夹 # 请自定义你自己的共享目录 sudo mkdir -p /exports/nfs4/homes sudo chmod -R 777 /exports/nfs4/homes# 这个可以根据no_root_squash标致选择设置。 # 如果不设…

Open FPV VTX开源之默认MAVLink设置

Open FPV VTX开源之默认MAVLink设置 1. 源由2. 准备3. 连接4. 安装5. 配置6. 测试6.1 启动wfb-ng服务6.2 启动wfb-ng监测6.3 启动QGroundControl6.4 观察测试结果 7. 总结8. 参考资料9. 补充9.1 telemetry_tx异常9.2 DEBUG串口部分乱码9.3 PixelPilot软件问题 1. 源由 飞控图传…

26个开源Agent开发框架调研总结(2)

根据Markets & Markets的预测&#xff0c;到2030年&#xff0c;AI Agent的市场规模将从2024年的50亿美元激增至470亿美元&#xff0c;年均复合增长率为44.8%。 Gartner预计到2028年&#xff0c;至少15%的日常工作决策将由AI Agent自主完成&#xff0c;AI Agent在企业应用中…

mark 一下conductor github

Netflix 关闭conductor 后&#xff0c;后续https://orkes.io/content/ 继续在维护&#xff0c;github地址如下 https://github.com/conductor-oss/conductor 最新release为3.21.11

PyCharm文档管理

背景&#xff1a;使用PyCharmgit做文档管理 需求&#xff1a;需要PyCharm自动识别docx/xslx/vsdx等文件类型&#xff0c;并在PyCharm内点击文档时唤起系统内关联应用(如word、excel、visio) 设置步骤&#xff1a; 1、file -》 settings -》file types 2、在Files opened i…

嘉立创画原理图和PCB

一、环境 进入立创EDA官网 注册登录的环节就不介绍了。 登录账号后&#xff0c;选择专业版 二、原理图 工程中&#xff0c;有原理图和PCB&#xff0c;这里选择原理图 那么接下来就是进行绘制 元器件在如下区域搜索使用。 双击进行放置&#xff0c;也可以左键提前预览。 网…

科创驱动 | 华望系统科技荣膺西湖区年度前沿创新新锐企业

2025年1月3日&#xff0c;由中共西湖区党委、西湖区人民政府主办的“新年第一会”—西湖区科技创新大会在杭州隆重举行。大会现场揭晓了西湖区年度科技创新团队与项目&#xff0c;并发布了“2024西湖区科技十大事件”与“西湖区五大年度科技榜单”。杭州华望系统科技有限公司榜…

Monorepo设置:新手指南

Monorepo是一种项目代码管理方法&#xff0c;指在单个代码仓库中管理多个项目&#xff0c;有助于简化代码共享、版本控制、构建和部署的复杂性&#xff0c;并提供更好的可重用性和协作性。 简单理解&#xff1a;所有项目都在一个代码仓库中 &#x1f4e6;&#xff0c;但这并不意…