React源码解析18(3)------ beginWork的工作流程

news2024/11/23 15:21:07

摘要

OK,经过上一篇文章。我们调用了:

const root = document.querySelector('#root');
ReactDOM.createRoot(root)

生成了FilberRootNode和HostRootFilber。
并且二者之间的对应关系也已经确定。

而下一步我们就需要调用render方法来讲react元素挂载在root上:

//第一节实现的jsx方法
const reactElement = jsx("div", {
  ref: "123",
  children: jsx("span", {
    children: "456"
  })
});
ReactDOM.createRoot(root).render(reactElement)

所以我们现在要实现ReactDOM.createRoot中返回的render方法。

1.update和updateQueue

首先我们思考一下,在React中,除了通过上面的render方法,会让React组件更新。还有setState等逻辑,也可以触发React的更新。
也就是说,我们要实现一个方法。在触发React组件更新时调用:updateContainer。

在实现updateContainer方法前,我们先实现一套机制,用来保存更新的内容。这里可以创建一个update.js用来写这部分内容:


//创建一个更新内容
function createUpdate(action) {
  return {
    action
  }
}

//给FilberNode创建一个更新队列
function createUpdateQueue() {
  return {
    shared: {
      pending: null
    }
  }
}

//在更新队列里添加更新内容
function enqueueUpdate(updateQueue, update) {
  updateQueue.shared.pending = update
}

//根据更新的内容,去更新FilberNode(this.setState)
function processUpdateQueue(baseState, pendingUpdate) {
  const result = {
    memoizedState: baseState
  }
  if(pendingUpdate !== null){
    const action = pendingUpdate.action;
    //setState(() => {}) 传入方法
    if(typeof action === 'function'){
      result.memoizedState = action(baseState);
    }else {
      //setState()
      result.memoizedState = action;
    }
  }
  return result;
}

这个时候,我们的更新相关的方法已经准备好了。现在就要开始干了。首先要在FilberNode上增加一个属性,updateQueue用来保存更新的内容:
this.updateQueue = null;

2.updateContainer方法

现在我们开始实现updateContainer方法,该方法接受两个参数,第一个是通过createContainer方法创建出来的FilberRootNode,第二个就是render方法传入的ReactElement。

function createRoot(root) {
  const filberRootNode = createContainer(root);
  return {
    render(element) {

    }
  }
}

function updateContainer(root, element) {
  
}

在方法里,我们思考一下,如果不考虑setState的情况。第一次渲染的时候,对于最外层的FilberNode,他需要更新的内容,不就是传入的element吗。

所以我们通过root.current拿到最外层的FilberNode。执行对应的更新操作:

function createRoot(root) {
  const filberRootNode = createContainer(root);
  return {
    render(element) {
      updateContainer(filberRootNode, element)
    }
  }
}

function updateContainer(root, element) {
  const hostRootFilber = root.current;
  const update = createUpdate(element);
  hostRootFilber.updateQueue = createUpdateQueue()
  enqueueUpdate(hostRootFilber.updateQueue, update);
  console.log(hostRootFilber)
}

我们将对应的节点打印出来看一下,最外层的FilberNode此时已经有了updateQueue,并且里面的内容就是对应的ReactElement
在这里插入图片描述

3.实现beginWork

OK,现在我们最外层的FilberNode已经准备好,我们开始准备构建Filber树。其实构建Filber树的过程,就是创建好所有的FilberNode,并且通过return,sibling,child这三个属性进行构建。

而表示整棵树的结构,都存在updateQueue中的ReactElement,我们就是要通过它去创建这颗Filber树。

现在我们不考虑有sibling属性的情况,只考虑有return和child属性的情况,创建beginWork方法:

function beginWork(nowFilberNode) {

}

function updateContainer(root, element) {
  const hostRootFilber = root.current;
  const update = createUpdate(element);
  hostRootFilber.updateQueue = createUpdateQueue()
  enqueueUpdate(hostRootFilber.updateQueue, update);
  beginWork(hostRootFilber);
}

我们主要要做的就是,在beginWork里面,创建好所有的fiberNode。并且找清楚他们之间的对应关系。所以我们的beginWork一定是一个递归的方法:
我们会判断当前filberNode的tag:

function beginWork(nowFilberNode) {
  switch (nowFilberNode) {
    case HostRoot: {
		return updateHostRoot(nowFilberNode); 
    }
    case HostComponent: {

    }
    case HostText: {

    }
    case FunctionComponent: {

    }
    default: {
      console.error('错误的类型')
    }
  }
}

由于第一次调用,传入的是最外面的filberNode,所以tag应该为HostRoot。我们针对于这种情况写一个方法updateHostRoot。

function updateHostRoot(filberNode) {
  const baseState = filberNode.memoizedState;
  const updateQueue = filberNode.updateQueue;
  const pending = updateQueue.shared.pending;
  updateQueue.shared.pending = null;
  const { memoizedState } = processUpdateQueue(baseState, pending);
  filberNode.memoizedProps = memoizedState;
  const nextChildren = filberNode.memoizedProps;
  console.log(nextChildren);
  console.log(filberNode);
}

对于首屏渲染,我们知道对于FilberNode来说,更新的内容就是他的子节点。所以我们更新好FilebrNode的updateQueue属性和memoizedState,memoizedProps属性后。

可以直接拿到它的子节点nextChildren,不过这个节点是ReactElement类型,我们要将它转换成FilberNode,所以我们还需要一个方法:reconcilerChildren。

function reconcileChildren(element) {
  let tag;
  if(element.$$typeof === REACT_ELEMENT_TYPE){
    tag = HostComponent;
  }else if(typeof element === 'string'){

  }
  return new FilberNode(tag, element.props, element.key)

}

我们创建好的子FilberNode,用element的props初始化FilberNode的penddingProps。
这个时候我们在updateHostRoot中调用该方法,并将子FilberNode打印出来。

function updateHostRoot(filberNode) {
  /**
  * 其他代码
  **/
  const newFilberNode = reconcileChildren(nextChildren);
  filberNode.child = newFilberNode;
  newFilberNode.return = filberNode
  console.log(newFilberNode);
  beginWork(newFilberNode)
}

可以看到子FilberNode和父节点的关系已经更新好,同时也将自己的ReactElement放在了pendingProps里。

在这里插入图片描述

Ok,对于HostRoot类型(最外层的FilberNode),我们有了updateHostRoot方法处理,那对于HostComponent类型,我们自然也需要updateHostComponent方法:

function updateHostComponent(filberNode) {
  const nextChildren = filberNode.pendingProps.children;
  const newFilberNode = reconcileChildren(nextChildren);
  filberNode.child = newFilberNode;
  newFilberNode.return = filberNode;
  beginWork(newFilberNode)
}

同样的,对于文本类型的节点,自然也不需要去给它创建FilberNode。这里面我们不做处理就好。

到这里,我们就已经简单的处理了只有child和return属性的Filber树,最终也可以打印出来这颗树的样子:
在这里插入图片描述
可以看到每个FilberNode都具有child和return两个属性。

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

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

相关文章

研究:ChatGPT在生成代码方面的准确率比抛硬币还低!

✍创作者:全栈弄潮儿 🏡 个人主页: 全栈弄潮儿的个人主页 🏙️ 个人社区,欢迎你的加入:全栈弄潮儿的个人社区 📙 专栏地址:AI大模型 ChatGPT真的能帮助程序员?研究&#…

【Opencv入门到项目实战】(八):图形直方图|傅里叶变换

所有订阅专栏的同学可以私信博主获取源码文件 文章目录 1.图像直方图1.1 直方图计算1.2 分通道读取1.3 mask操作(掩码操作) 2.傅里叶变换2.1 频率转换结果2.2 高通和低通滤波器 1.图像直方图 1.1 直方图计算 直方图是一种用于可视化数据分布的图表形式…

朋友圈截图生成,制作朋友圈网页

使用教程可以自己看工具的使用手册。 Windows电脑版: https://imageio.jscs.top/zip/wxchat-moment-windows Mac电脑版: https://imageio.jscs.top/zip/wxchat-moment-mac 这款神器的主要功能是朋友圈评论截图生成器,而且还具有以下功能中…

cesium学习记录05-支持的主要数据格式与服务

1. 矢量数据: 1.1. GeoJSON 定义: 一个基于JSON的地理数据格式,Cesium支持GeoJSON的直接加载。 例子: 加载一个简易故宫建筑的GeoJSON数据。 代码: /*** 添加故宫geojson数据*/AddGuGong() {var viewer this.v…

【Linux从入门到精通】文件操作(C语言vs系统调用)

文章目录 一、C语言的文件IO相关函数操作 1、1 fopen与fclose 1、2 fwrite 1、3 fprintf与fscanf 1、4 fgets与fputs 二、系统调用相关接口 2、1 open与close 2、2 write和read 三、简易模拟实现cat指令 四、总结 🙋‍♂️ 作者:Ggggggtm 🙋‍…

AP2915DC-DC降压恒流驱动IC LED电源驱动芯片 汽车摩托电动车灯

AP2915 是一款可以一路灯串切换两路灯串的降压 恒流驱动器,高效率、外围简单、内置功率管,适用于 5-80V 输入的高精度降压 LED 恒流驱动芯片。内置功 率管输出功率可达 12W,电流 1.2A。 AP2915 一路灯亮切换两路灯亮,其中一路灯亮可 以全亮&a…

C++,文本文件,读取文件

代码演示&#xff1a; #include<iostream> using namespace std; #include<string> #include<fstream>void test() {//1、包含头文件//2、创建流对象ifstream ifs;//3、打开文件并判断文件是否成功ifs.open("test.txt", ios::in);if (!ifs.is_ope…

问道管理:A股缩量整理 新股上演久违暴涨模式

周三&#xff0c;大盘低开后震动&#xff0c;三大指数小幅跌落&#xff0c;创业板指相对偏强。 早盘开盘后&#xff0c;沪指、深证成指弱势震动&#xff0c;创业板指探底上升翻红&#xff0c;盘面热门乏善可陈。午后三大指数震动走弱&#xff0c;创业板指再度翻绿。医药板块活…

Vue 实现重定向、404和路由钩子(六)

一、重定向 1.1 修改 Main.vue <template><div><el-container><el-aside width"200px"><el-menu :default-openeds"[1]"><el-submenu index"1"><template slot"title"><i class"…

伪原创神码ai怎么样【php源码】

这篇文章主要介绍了python汉化补丁包下载&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 火车头采集ai伪原创插件截图&#xff1a; ** Spyder汉化&#xff08;python汉化&…

在vue项目使用数据可视化 echarts ,柱状图、折线图、饼状图使用示例详解及属性详解

官网地址&#xff1a;Apache ECharts ​一、下载插件并在页面中引入 npm install echarts --save 页面导入&#xff1a; import * as echarts from echarts 全局导入&#xff1a; main.js 中&#xff0c;导入并注册到全局 import echarts from echarts Vue.prototype.$echart…

【云存储】【腾讯云】【阿里云】【b2】【google drive】【one drive】【s3】【azure】对比

【1】google drive 【2】b2 price 【3】腾讯云对象存储 文档中心 > 对象存储 > 开发者指南 > 对象 > 存储类型 > 存储类型概述 文档中心 > 对象存储 > 购买指南 > 计费项 > 数据取回费用

【计算机组成原理】24王道考研笔记——第四章 指令系统

第四章 指令系统 一、指令系统 指令是指示计算机执行某种操作的命令&#xff0c;是计算机运行的最小功能单位。一台计算机的所有指令的集合构成该 机的指令系统&#xff0c;也称为指令集。 指令格式&#xff1a; 1.1分类 按地址码数目分类&#xff1a; 按指令长度分类&…

AttentionFreeTransformer 源码解析(一):AFTFull、AFTSimple、AFTLocal

我觉得源码写的很好懂&#xff0c;我就不加注释了&#xff0c;直接上计算流程图。 AFTFull class AFTFull(nn.Module):def __init__(self, max_seqlen, dim, hidden_dim64):super().__init__()max_seqlen: the maximum number of timesteps (sequence length) to be fed indim…

echarts柱状图X轴增加table列表显示数据,多y轴

效果图 完整配置 data(){return{chart1:null,chartType1:1,data:{years:{date:[2015,2016,2017,2018,2019,2020,2021,2022,2023],business:[10,23,26,33,43,58,50,45,66],profit:[3,4,6,7,8,5,7,8,12],proportion:[12,8,15,20,12,16,13,15,9]},months:{date:[1月, 2月,3月, 4月…

在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配

1.Cadence 17.2 配置CIS数据库报&#xff1a;ERROR(ORCIS-6245): Database Operation Failed 安装cadance17.2以上版本时&#xff0c;ERROR(ORCIS-6245): Database Operation Failed_收湾湾的博客-CSDN博客 原因是ODBC数据库没有配置&#xff0c;或者没有驱动&#xff0c; 驱…

侯捷 C++ part2 兼谈对象模型笔记——3 模板

3 模板 3.1 类模板/函数模板 补充&#xff1a;只有模板的尖括号中<>&#xff0c;关键字 typename 和 class 是一样的 3.2 成员模板 它即是模板的一部分&#xff0c;自己又是模板&#xff0c;则称为成员模板 其经常用于构造函数 ctor1 这是默认构造函数的实现&#…

阿里云服务器免费申请使用限制条件及云主机配置

阿里云服务器免费试用申请链接入口&#xff0c;阿里云个人用户和企业用户均可申请免费试用&#xff0c;最高可以免费使用3个小时&#xff0c;阿里云服务器网分享阿里云服务器免费试用申请入口链接及云服务器配置&#xff1a; 目录 阿里云服务器免费试用 企业用户免费服务器试…

解决Qt的列表加载大量数据卡顿的问题

问题概述 本人在使用QListView插入大量数据时&#xff0c;界面卡顿十分严重。数据量大概只有上千左右&#xff0c;但是每个Item的内容比较多。当数据不停地插入一段时间后&#xff0c;卡顿到鼠标的移动都有点困难。 解决思路 QListView是典型的MVC思想的产物。界面呈现出来的数…

CorelDRAW(CDR) 2023中文版64位下载新功能教程

CorelDRAW2023&#xff08;简称CDR2023&#xff09;是一款非常专业的图形设计工具&#xff0c;该产品推出了全新的2023版本&#xff0c;在功能和体验上更进一步&#xff0c;最新的填充和透明设备功能可以完全控制任何类型的纹理&#xff0c;适用于网络摄影、印刷项目、艺术、排…