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树,并处理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;
  }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/954345.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一体机cell服务器更换内存步骤

一体机cell服务器更换内存步骤&#xff1a; #1、确认grdidisk状态 cellcli -e list griddisk attribute name,asmmodestatus,asmdeactivationoutcome #2、offline griddisk cellcli -e alter griddisk all inactive #3、确认全部offline后进行关机操作 shutdown -h now #4、开…

uni-app编写微信小程序使用uni-popup搭配uni-popup-dialog组件在ios自动弹出键盘。

uni-popup-dialog 对话框 将 uni-popup 的type属性改为 dialog&#xff0c;并引入对应组件即可使用对话框 &#xff0c;该组件不支持单独使用 示例 <button click"open">打开弹窗</button> <uni-popup ref"popup" type"dialog"…

SYS_OP_MAP_NONNULL NULL的等值比较

无意在数据库中发现了这个操作SYS_OP_MAP_NONNULL。 SYS_OP_MAP_NONNULL应该不是数据库中的对象&#xff0c;因为在DBA_OBJECTS中根本找不到它&#xff0c;而在STANDARD和DBMS_STANDARD包中也找不到函数说明。 SQL> SELECT * 2 FROM DBA_OBJECTS 3 WHERE OBJECT_NAME…

基于Java的百度AOI数据解析与转换的实现方法

目录 前言 一、AOI数据结构简介 1、官网的实例接口 2、响应参数介绍 二、Java对AOI数据的解析 1、数据解析流程图 2、数据解析实现 3、AOI数据解析成果 三、总结 前言 在当今信息化社会&#xff0c;地理信息数据在城市规划、交通管理、商业选址等领域扮演着越来越重要的…

深度学习中的学习率调度器(scheduler)分析并作图查看各方法差异

文章目录 1. 指数衰减调度器&#xff08;Exponential Decay Scheduler&#xff09;工作原理适用场景实现示例 2. 余弦退火调度器&#xff08;Cosine Annealing Scheduler&#xff09;工作原理适用场景实现示例 3. 步长衰减调度器&#xff08;Step Decay Scheduler&#xff09;工…

IPSEC实验

实验要求 某小型企业为扩大网络规模&#xff0c;设立分公司&#xff0c;今日要求分公司能够访问主公司对应的资源&#xff0c;为此很是苦恼 为满足其跨区域访问对端网络的要求&#xff0c;现要求使用IPSEC搭建隧道使得分公司能够与主公司通讯 实验拓扑 该公司与分公司拓扑大…

[c语言日寄]精英怪:三子棋(tic-tac-toe)3命慢通[附免费源码]

哈喽盆友们&#xff0c;今天带来《c语言》游戏中[三子棋boss]速通教程&#xff01;我们的目标是一边编写博文&#xff0c;一边快速用c语言实现三子棋游戏。准备好瓜子&#xff0c;我们计时开始&#xff01; 前期规划 在速通中&#xff0c;我们必须要有清晰的前期规划&#xf…

TensorFlow DAY3: 高阶 API(Keras,Estimator)(完)

TensorFlow 作为深度学习框架&#xff0c;当然是为了帮助我们更便捷地构建神经网络。所以&#xff0c;本次实验将会了解如何使用 TensorFlow 来构建神经网络&#xff0c;并学会 TensorFlow 构建神经网络的重要函数和方法。 知识点 Keras 顺序模型Keras 函数模型Keras 模型存储…

数据结构(Java版)第九期:LinkedList与链表

专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 目录 一、LinkedList的模拟实现 1.1. 头插法 1.2. 尾插法 1.3. 插入中间节点 1.4. 删除某个节点 1.5. 删除所有为key的元素 二、LinkedList的使用 2.1. 什么是LinkedList 2.2. LinkedList的使⽤ 三、…

ubuntu18.04开发环境下samba服务器的搭建

嵌入式linux的发展很快&#xff0c;最近准备在一个新项目上采用新一代的linux核心板&#xff0c;发现linux内核的版本已经更新到5.4以上甚至6.0以上&#xff1b;之前常用的linux内核版本是2.6.4&#xff0c;虽然在某些项目上还能用但是明显跟不上时代的步伐了&#xff0c;所以要…

【优先算法】滑动窗口--(结合例题讲解解题思路)(C++)

目录 1. 例题1&#xff1a;最大连续1的个数 1.1 解题思路 1.2代码实现 1.3 错误示范如下&#xff1a;我最开始写了一种&#xff0c;但是解答错误&#xff0c;请看&#xff0c;给大家做个参考 2. 将 x 减到 0 的最小操作数 2.1解题思路 2.2代码实现 1. 例题1&#xff…

数据结构二叉树-C语言

数据结构二叉树-C语言 1.树1.1树的概念与结构1.2树的相关术语1.3树的表示1.4树形结构实际运用场景 2.二叉树2.1概念与结构2.2特殊的二叉树2.2.1满二叉树2.2.2完全二叉树 2.3二叉树存储结构2.3.1顺序结构2.3.2链式结构 3.实现顺序结构的二叉树4.实现链式结构二叉树4.1前中后序遍…

Qt/C++进程间通信:QSharedMemory 使用详解(附演示Demo)

在开发跨进程应用程序时&#xff0c;进程间通信&#xff08;IPC&#xff09;是一个关键问题。Qt 框架提供了多种 IPC 技术&#xff0c;其中 QSharedMemory 是一种高效的共享内存方式&#xff0c;可以实现多个进程之间快速交换数据。本文将详细讲解 QSharedMemory 的概念、用法及…

【vue3项目使用 animate动画效果】

vue3项目使用 animate动画效果 前言一、下载或安装npm 安装 二、引入组件三、复制使用四、完整使用演示总结 前言 提示&#xff1a;干货篇&#xff0c;不废话&#xff0c;点赞收藏&#xff0c;用到会后好找藕~ 点击这里&#xff0c;直接看官网哦 &#x1f449; 官网地址&#…

Android 15应用适配指南:所有应用的行为变更

Android系统版本适配&#xff0c;一直是影响App上架Google Play非常重要的因素。 当前Google Play政策规定 新应用和应用更新 必须以 Android 14&#xff08;API 级别 34&#xff09;为目标平台&#xff0c;才能提交到Google Play。现有应用 必须以 Android 13&#xff08;AP…

qml TargetDirection详解

1、概述 TargetDirection是QML&#xff08;Qt Modeling Language&#xff09;中一个用于指定粒子系统中粒子移动方向的类型。它允许粒子朝向一个目标点移动&#xff0c;这个目标点可以是QML界面上的一个具体位置&#xff0c;也可以是另一个QML元素的中心。TargetDirection通常…

Linux C 使用ZBar库解析二维码和条形码

1. 编译zbar库 下载 zbar 库源码&#xff0c;这里需要注意下&#xff0c;如果识别的二维码中有中文的话&#xff0c;会出现乱码&#xff0c;一般二维码里中文为UTF-8编码&#xff0c;zbar会默认给你把UTF-8转换为ISO8859-1。有两种解决办法&#xff0c;一是自己再转换一下编码…

金融项目实战 06|Python实现接口自动化——日志、实名认证和开户接口

目录 一、日志封装及应用&#xff08;理解&#xff09; 二、认证开户接口脚本编写 1、代码编写 1️⃣api目录 2️⃣script目录 2、BeautifulSoup库 1️⃣简介及例子 2️⃣提取html数据工具封装 3、认证开户参数化 一、日志封装及应用&#xff08;理解&#xff09; &…

基于springboot+vue+微信小程序的宠物领养系统

基于springbootvue微信小程序的宠物领养系统 一、介绍 本项目利用SpringBoot、Vue和微信小程序技术&#xff0c;构建了一个宠物领养系统。 本系统的设计分为两个层面&#xff0c;分别为管理层面与用户层面&#xff0c;也就是管理者与用户&#xff0c;管理权限与用户权限是不…

【微服务】面试题 5、分布式系统理论:CAP 与 BASE 详解

分布式系统理论&#xff1a;CAP 与 BASE 详解 一、CAP 定理 背景与定义&#xff1a;1998 年由加州大学科学家埃里克布鲁尔提出&#xff0c;分布式系统存在一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;、分区容错性&#xff08;Part…