浅谈React Fiber工作原理

news2024/11/15 21:35:04

静态数据结构

每个 Fiber 节点对应一个组件,保存了该组件的类型,对应的 DOM 节点的对应信息。

FiberRootNode 有且仅有一个,而 rootFiber 可以有多个,因为我们可以挂载多个应用(也就是多次调用ReactDOM.render

function App(props) {
  const [age, setAge] = useState(24);
  return (
    <div>
      chenjiang
      {age}
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

最终形成数据结构如下:

请添加图片描述

Fiber 的数据结构

function FiberNode(tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode) {
  // Instance

  // 组件的类型 FunctionComponent、classComponent、HostComponent(指的是DOM节点对应的Fiber节点)
  this.tag = tag;

  this.key = key;

  // 大多数情况下于tag相同,使用React.memo包裹时候,elementType和tag不同
  this.elementType = null;

  // 对于FunctionComponent,指函数本身
  // 对于ClassComponent,指class
  // 对于HostComponet,指的是DOM节点tagName
  this.type = null;

  // 对于HostComponent来说指的是对应的真实的DOM节点
  this.stateNode = null;

  // 以下属性用于连接其他Fiber节点形成Fiber树。

  // 指向父fiber节点
  this.return = null;

  // 指向第一个子fiber节点
  this.child = null;

  // 指向第一个兄弟fiber节点
  this.sibling = null;
  this.index = 0;

  // ref属性
  this.ref = null;

  // 新传入的 props
  this.pendingProps = pendingProps;

  // 之前的 props
  this.memoizedProps = null;

  // 更新队列,用于暂存 setState 的值
  this.updateQueue = null;

  // 之前的 state
  this.memoizedState = null;
  this.dependencies = null;

  this.mode = mode;

  // 保存本次更新会造成的DOM操作。比如删除,移动
  this.flags = NoFlags;
  this.nextEffect = null;

  this.firstEffect = null;
  this.lastEffect = null;

  this.lanes = NoLanes;
  this.childLanes = NoLanes;

  //用于链接新树和旧树;旧->新,新->旧
  this.alternate = null;
}

动态的工作单元

Fiber 可以理解成一个工作单元,每次执行完一个工作单元,react 就会检查还剩余多少时间,如果没有就把控制权交还给浏览器。React Fiber 与浏览器的核心交互过程如下:

undefined

首先 React 向浏览器请求调度,浏览器在一帧中如果还有空闲时间,会去判断是否存在待执行任务,不存在就直接将控制权交给浏览器,如果存在就会执行对应的任务,执行完成后会判断是否还有时间,有时间且有待执行任务则会继续执行下一个任务,否则就会将控制权交给浏览器。

Fiber 可以被理解为划分一个个更小的工作单元,它是把一个大任务拆分为了很多个小块任务,一个小块任务的执行必须是一次完成的,不能出现暂停,但是一个小块任务执行完后可以移交控制权给浏览器去响应用户,从而不用等待大任务一直执行完成再去响应用户。

架构(双缓存工作机制)

什么是双缓存

当我们用canvas绘制动画,每一帧绘制前都会调用ctx.clearRect清除上一帧的画面。如果当前帧画面计算量比较大,导致清除上一帧画面到绘制当前帧画面之间有较长间隙,就会出现白屏闪烁。

为了解决这个问题,我们可以在内存中绘制当前帧动画,绘制完毕后直接用当前帧替换上一帧画面,由于省去了两帧替换间的计算时间,不会出现从白屏到出现画面的闪烁情况。

这种在内存中构建并直接替换的技术叫做双缓存。

React使用“双缓存”来完成Fiber树的构建与替换——对应着DOM树的创建与更新。

双缓存 Fiber 树

React 中存在两棵树,一颗为current Fiber tree,另外一颗为workInProgress Fiber tree

  • current Fiber tree也就是当前页面中显示内容对应的 Fiber 树,每个 Fiber 节点成为 current fiber。
  • workInProgress Fiber tree正在内存中构建的 Fiber 树。

两颗树的 fiber 节点是通过alternate属性进行连接的。

currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;

React 的根节点(FiberRootNode)通过 current 指针在不同的 Fiber 树的 rootFiber 间切换来实现 Fiber 树的切换。

请添加图片描述

Fiber 树的构建(挂载阶段、更新阶段)

再次强调:FiberRootNode 有且仅有一个,而 rootFiber 可以有多个,因为我们可以挂载多个应用(也就是多次调用ReactDOM.render

以下代码为例:

function App(props) {
  const [age, setAge] = useState(24);
  return (
    <div
      onClick={() => {
        setAge(25);
      }}
    >
      {age}
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

挂载阶段(mount 阶段)

首次调用ReactDOM.render就会创建FiberRootNode,每次调用ReactDOM.render就会创建当前应用的根节点RootFiber,由于在首屏渲染之前页面是空白的,因此RootFiber不存在子节点。

请添加图片描述

挂载阶段流程如下(首屏渲染)

首先创建 fiber 树的根节点RootFiber,在两棵树之间都存在的 Fiber 节点用alternate连接,接下来采用深度遍历的方式创建 Fiber 树,当workInProgress Fiber tree完成了渲染,最后 FiberRootNode 的 current 指针就指向workInProgress Fiber tree的根节点,此时就变成current Fiber tree

请添加图片描述

更新阶段 (update 阶段)

每次触发更新都会重新创建一颗workInProgress Fiber Treecurrent Fiber与本次更新返回的JSX做对比,生成workInProgress Fiber的过程就是 diff 算法,update 阶段与 mount 阶段,最大的区别就是是否有 diff 算法。
请添加图片描述

参考文章:

  • https://juejin.cn/post/6844904202104209415
  • https://juejin.cn/post/6943896410987659277

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

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

相关文章

注解@EnableAutoConfiguration

上一节已经看了Import注解&#xff0c;而EnableAutoConfiguration注解中就引用了此注解 AutoConfigurationPackage Import(AutoConfigurationImportSelector.class) public interface EnableAutoConfiguration { 所以接下来可以看一下AutoConfigurationImportSelector类&…

Educational Codeforces Round 144 (Rated for Div. 2) E

人菜瘾大还是忍不住打了这场比赛&#xff0c;b卡了半小时&#xff0c;甚至还写了一个最长公共子序列然后喜提wa2&#xff0c;但是c,d还是过的比较快&#xff0c;最后排名rk175有惊无险的上分了&#xff0c;e题赛时一眼想出思路&#xff0c;但是我的实现能力有限&#xff0c;没能…

谷歌关键词排名上首页需要多久【2023年实战数据】

本文主要分享2023年实战得出谷歌做新站关键词排名到首页所需要的时间周期测试。 本文由光算创作&#xff0c;有可能会被剽窃和修改&#xff0c;我们佛系对待这种行为吧。 谷歌关键词排名上首页需要多久&#xff1f; 答案是&#xff1a;90天左右。 具体以下图实战数据为主 关…

【总结】记一次log4j包冲突引发es类找不到的问题

问题现象 某天&#xff0c;某个应用搞新的迭代&#xff0c;突然报ElasticSearch 7.17.5 相关操作都失败了&#xff0c;且问题是必现&#xff0c;本地启动也能稳定复现。组内小伙伴按照es jar包冲突排查了一番&#xff0c;无果&#xff0c;于是问题转交给我来排查。 错误信息是…

计算机网络(第三版) 胡亮 第四章知识点总结

计算机网络&#xff08;第三版&#xff09; 胡亮 第四章知识点总结 学习指导 1、掌握询问/确认、轮询/选择模式的使用场合与工作方式 2、掌握停止等待协议的流量控制和差错控制&#xff0c;会进行相关定量的计算。 3、掌握滑动窗口协议中的回退N和选择控制的工作方式 4、了…

重拾JS基础:掌握闭包和作用域链的秘密,让你代码更加简洁优雅

在 JavaScript 中&#xff0c;闭包和作用域链是两个重要的概念&#xff0c;对于理解 JavaScript 中函数的工作方式和实现高级功能非常关键。本文将介绍闭包和作用域链的概念、如何创建和使用闭包&#xff0c;以及如何避免常见的陷阱和错误。 引言 JavaScript 是一门具有函数式编…

基于神经网络的滑模鲁棒控制

目录 前言 1.双关节机械手臂模型 2.神经网络自适应律设计 3. 滑模控制律设计 4. 仿真分析 4.1 仿真模型 4.2 仿真结果 4.3 小结 5 学习问题 前言 上一篇文章我介绍了神经网络补偿的机理&#xff0c;只不过控制律不同&#xff0c;本章我们结合滑模理论设计控制律&#…

不同规划企业对CRM系统的性价比要求

很多企业在选型时关心CRM客户管理系统的价格&#xff0c;有人对CRM的价格完全没有概念&#xff0c;也有的人先问价格再看其他。CRM价格在系统选型中到底有多重要&#xff1f;如何评估CRM价格和价值之间的关系&#xff1f;企业规模对CRM系统价格有什么影响&#xff1f; CRM软件…

Android系统10 RK3399 init进程启动(四十八) init第一阶段分析

配套系列教学视频链接&#xff1a;安卓系列教程之ROM系统开发-百问100ask说明系统&#xff1a;Android10.0设备&#xff1a; FireFly RK3399 &#xff08;ROC-RK3399-PC-PLUS&#xff09;前言本文通过代码梳理的方式&#xff0c;给大家介绍Android init祖先进程第一阶段的工作流…

MAC地址申请MAC码购买流程MAC地址哪里申请MAC地址作用

众所周知mac地址号段全世界都是由美国一家政府机构IEEE进行分配的&#xff0c;也是由他们进行管理的。我站具有丰富的MAC地址申请经验&#xff0c;可以帮助客户有效的快速高效的完成MAC地址的申请。关于mac地址购买种类、范围、方式、费用详情如下。 一、服务项目&#xff1a;…

vue3、vite、pinia 快速入门

准备 开发工具及插件IDE:vscode,WebStorm插件&#xff1a;Auto Close Tag、Auto Rename Tag、Live Server通过“&#xff01;”快速生成html模板正式学习安装vue通过CDN的方式导入vue<script src"" target"_blank">https://unpkg.com/vue3/dist/vue.…

mysql数据库之索引分类

分类含义特点关键字主键索引针对于表中主键创建的索引默认自动创建&#xff0c;只能有一个primary唯一索引避免同一个表中某数据列中的值重复可以有多个unique常规索引快速定位特定数据可以有多个全文索引全文索引查找的是文本中的关键词&#xff0c;而不是比较索引中的值可以有…

01 Android基础--广播

01 Android基础--广播什么是广播&#xff1f;广播的分类本地广播LocalBroadcastManager什么是广播&#xff1f; 传输信息的机制。 主要记住三个要素&#xff1a;1.广播(Broadcast) - 用于发送广播; 2.广播接收器(BroadcastReceiver) - 用于接收广播&#xff1b;3.意图内容(Inte…

【活学活用掌握trap命令】

trap 命令用于指定在接收到信号后将要采取的动作&#xff0c;常见的用途是在脚本程序被中断时完成清理工作。当 shell 接收到 sigspec 指定的信号时&#xff0c; arg 参数(通常是执行命令)会被读取&#xff0c;并被执行。 1. 命令介绍 开始掌握基本的使用方式和方法 [1] 语法…

云计算简介

本文为copy他人编写的文档&#xff0c;由于不确认作者名称&#xff0c;故无法标记来源&#xff08;实际来源是群pdf文档&#xff09;&#xff0c;暂时发文为原创&#xff0c;因为无法贴出原文链接&#xff01; 云原生的前世今生 随着公有云和私有云的广泛部署&#xff0c;云计…

1.1 Linux开发环境搭建

1. Ubuntu服务器安装ssh工具&#xff0c;然后使用xshell连接 查看Ubuntu服务器的IP地址时&#xff0c;如果ifconfig失败&#xff0c;需要先安装一下net工具 sudo apt install openssh-server sudo apt install net-tools2. 打开vscode&#xff0c;安装Remote Development拓展…

操作系统——11.线程概念和多线程模型

这篇文章我们来讲一下操作系统中的线程概念和多线程模型 目录 1.概述 2.线程 2.1问题提出 2.2线程概念 2.3带来的变化 2.4线程的属性 2.5线程的实现方式 2.5.1用户级线程 2.5.2内核级线程 2.5.3相互组合 2.6多线程模型 2.6.1多对一模型 2.6.2一对一模型 2.6.3多…

操作系统权限提升(二十二)之Linux提权-SUDO滥用提权

系列文章 操作系统权限提升(十八)之Linux提权-内核提权 操作系统权限提升(十九)之Linux提权-SUID提权 操作系统权限提升(二十)之Linux提权-计划任务提权 操作系统权限提升(二十一)之Linux提权-环境变量劫持提权 SUDO滥用提权 SUDO滥用提权原理 sudo是linux系统管理指令&…

【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

避坑宝 v1.0.0 基于SpringBootuniapp企业黑红名单吐槽小程序 &#x1f4da;项目介绍 避坑宝 【避坑宝】企业黑红名单吐槽小程序是一个具有吐槽发布企业信息的一个平台&#xff0c;言论自由&#xff0c;评判自定&#xff0c;便于我们打工人分辨企业好坏。技术栈基于SpringBoot…

墨者靶场--报错盲注

引入一下报错注入的知识点&#xff0c;参考【https://www.cnblogs.com/X-caiji/p/13186633.html】 输入测试语句1 and 11--,正常回显 1 and 12-- 无任何报错信息&#xff0c;但是可以确定我们输入的内容确实是被执行了。 那么可以考虑是盲注 一般在实战过程中就需要考虑各种各…