当前位置: 首页 > news >正文

【 React 】React JSX 转换成真实DOM的过程?

1. 是什么

react通过将组件编写的JSX映射到屏幕,以及组件中的状态发生了变化之后React会将这些「变化」更新到屏幕上
在前面文章了解中,JSX通过babel最终转化成React.createElement这种形式,例如:

<div>< img src="avatar.png" className="profile" /><Hello />
</div>

会被babel 转换成如下:

React.createElement("div",null,React.createElement("img", {src: "avatar.png",className: "profile"}),React.createElement(Hello, null) 
);

在转化过程中,babel在编译时会判断JSX中组件的首字母:

  • 当首字母为小写时,其被认定为原生DOM标签,createElement的第一个变量被编译为字符串
  • 当首字母为大写时,其被认定为自定义组件,createElement的第一个变量被编译为对象

最终都会通过RenderDOM.render(…)方法进行挂载,如下:

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

2. 过程

在react中,节点大致可以分成四个类别:

  • 原生标签节点
  • 文本节点
  • 函数组件
  • 类组件

如下所示:

class ClassComponent extends Component {static defaultProps = {color: "pink"};render() {return ( <div className="border"> <h3>ClassComponent</h3> <p className={this.props.color}>{this.props.name}</p ></div> ); }
}
function FunctionComponent(props) {return ( <div className="border">FunctionComponent<p>{props.name}</p ></div> ); 
}
const jsx = ( <div className="border"><p>xx</p > < a href=" ">xxx</ a> <FunctionComponent name=" " /><ClassComponent name=" " color="red" /></div> 
);

这些类别最终都会被转化成React.createElement这种形式
React.createElement其被调用时会传入标签类型type,标签属性props及若干子元素children ,作用是生成一个虚拟Dom对象,如下所示:

function createElement(type, config, ...children) {if (config) {delete config.__self;delete config.__source; }//源码中做了详细处理,比如过滤掉 ! key ref等const props = {...config,children: children.map(child =>typeof child === "object" ? child : createTextNode(child) ) };return {type,props}; 
}
function createTextNode(text) {return {type: TEXT,props: {children: [],nodeValue: text} }; 
}
export default {createElement
};

createElement会根据传入的节点信息进行一个判断:

  • 如果是原生标签节点,type是字符串,如div、span
  • 如果是文本节点,type就没有,这里是TEXT
  • 如果是函数组件,type是函数名
  • 如果是类组件,type是类名

虚拟DOM会通过ReactDOM.render进行渲染成真实DOM,使用方法如下:

ReactDOM.render(element,container[,callback])

当首次调用时,容器节点里的所有DOM元素都会被替换,后续的调用则会使用React的diff算法进行高效的更新
如果提供了可选的回调函数callback ,该回调将在组件被渲染或更新之后被执行render大致实
现方法如下:

function render(vnode, container) {console.log("vnode", vnode); //虚拟 DOM 对象// vnode _> nodeconst node = createNode(vnode, container);container.appendChild(node); 
}// 创建真实DOM节点
function createNode(vnode, parentNode) {let node = null;const {type, props} = vnode;if (type === TEXT) {node = document.createTextNode("");} else if (typeof type === "string") {node = document.createElement(type); } else if (typeof type === "function") {node = type.isReactComponent? updateClassComponent(vnode, parentNode) : updateFunctionComponent(vnode, parentNode); } else {node = document.createDocumentFragment(); }reconcileChildren(props.children, node);updateNode(node, props);return node;}//遍历下子 vnode 然后把子vnode-> 真实DOM 再插入到父node中
function reconcileChildren(children, node) {for (let i = 0; i < children.length; i++) {let child = children[i];if (Array.isArray(child)) {for (let j = 0; j < child.length; j++) {render(child[j], node); } } else {render(child, node); } } 
}
function updateNode(node, nextVal) {Object.keys(nextVal) .filter(k => k !== "children") .forEach(k => {if (k.slice(0, 2) === "on") { node.addEventListener(eventName, nextVal[k]); } else {node[k] = nextVal[k]; } }); 
}
//返回真实 dom节点
// 执行函数
function updateFunctionComponent(vnode, parentNode) {const {type, props} = vnode;let vvnode = type(props);const node = createNode(vvnode, parentNode);return node; 
}// dom// 先实例化,再执行render函数
function updateClassComponent(vnode, parentNode) {const {type, props} = vnode;let cmp = new type(props);const vvnode = cmp.render();const node = createNode(vvnode, parentNode);return node; 
}
export default {render
};

3. 总结

渲染流程如下所示:

  • 使用React.createElement或JSX编写React组件,实际上所有的JSX代码最后都会转换成React.createElement(…),Babel帮助我们完成了这个转换的过程。
  • createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
  • ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM

相关文章:

【 React 】React JSX 转换成真实DOM的过程?

1. 是什么 react通过将组件编写的JSX映射到屏幕&#xff0c;以及组件中的状态发生了变化之后React会将这些「变化」更新到屏幕上 在前面文章了解中&#xff0c;JSX通过babel最终转化成React.createElement这种形式&#xff0c;例如&#xff1a; <div>< img src"…...

[Open3d]: 知识记录

python api 官方手册&#xff1a;http://www.open3d.org/docs/release/ 可视化&#xff1a;http://www.open3d.org/docs/release/tutorial/visualization/visualization.html python-vis 参考代码&#xff1a;https://github.com/isl-org/Open3D/tree/master/examples/python/v…...

css面试题

1、css盒模型 a、标准盒模型---在标准盒模型中&#xff0c;width的宽度指的是content的宽度 b、怪异盒模型---在怪异盒模型中&#xff0c;width的宽度等于contentborderpadding 切换盒子模型的话&#xff0c;使用box-sizing。 2、link和import的区别 a、link是html标签&#x…...

vscode调试launch.json常用格式

1、简单的模版 定义一个简单的模版如下&#xff1a; {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387"version": "0.2.0","configuration…...

巨细!Python爬虫详解

爬虫&#xff08;又称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在 FOAF 社区中间&#xff0c;更经常的称为网页追逐者&#xff09;&#xff1b;它是一种按照一定的规则&#xff0c;自动地抓取网络信息的程序或者脚本。 如果我们把互联网比作一张大的蜘蛛网&#xff0c;那…...

项目中如何进行限流(限流的算法、实现方法详解)

❤ 作者主页&#xff1a;李奕赫揍小邰的博客 ❀ 个人介绍&#xff1a;大家好&#xff0c;我是李奕赫&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 记得点赞、收藏、评论⭐️⭐️⭐️ &#x1f4e3; 认真学习!!!&#x1f389;&#x1f389; 文章目录 限流的算法漏…...

https在win7的环境下如何配置

https在win7的环境下如何配置&#xff1f;在Windows7环境下配置https&#xff0c;需要完成以下步骤&#xff1a; 1&#xff09;安装Web服务器软件 可以选择安装常用的Web服务器软件&#xff0c;如Apache、Nginx或IIS&#xff0c;这些服务器软件都支持https。 2&#xff09;获…...

Day69:WEB攻防-Java安全JWT攻防Swagger自动化算法签名密匙Druid泄漏

目录 Java安全-Druid监控-未授权访问&信息泄漏 黑盒发现 白盒发现 攻击点 Java安全-Swagger接口-导入&联动批量测试 黑盒发现 白盒发现 自动化发包测试 自动化漏洞测试 Java安全-JWT令牌-空算法&未签名&密匙提取 识别 JWT 方式一&#xff1a;人工识…...

Python Windows系统 虚拟环境使用

目录 1、安装 2、激活 3、停止 1、安装 1&#xff09;为项目新建一个目录&#xff08;比如&#xff1a;目录命名为learning_log&#xff09; 2&#xff09;在终端中切换到这个目录 3&#xff09;执行命令&#xff1a;python -m venv ll_env&#xff0c;即可创建一个名为ll…...

栈和队列的学习

存储方式分两类&#xff1a;顺序存储和链式存储 栈&#xff1a;只允许从一端进行数据插入和删除的线性表&#xff1a;先进后出 FILO 队列&#xff1a;只允许从一端进行数据插入&#xff0c;另一端进行数据删除的线性表&#xff1a;先进先出 FIFO 栈 创建空栈&#xff0c;创建…...

【机器学习】基于机器学习的分类算法对比实验

摘要 基于机器学习的分类算法对比实验 本论文旨在对常见的分类算法进行综合比较和评估&#xff0c;并探索它们在机器学习分类领域的应用。实验结果显示&#xff0c;随机森林模型在CIFAR-10数据集上的精确度为0.4654&#xff0c;CatBoost模型为0.4916&#xff0c;XGBoost模型为…...

民航电子数据库:mysql与cae建表语法差异

目录 一、场景二、语法差异 一、场景 1、使用CAEMigrator-1.0.exe将mysql数据库迁移至cae数据库时&#xff0c;迁移速度非常慢&#xff0c;而且容易卡死&#xff08;可能是部署cae数据库的服务器资源不足导致&#xff09; 2、所以将mysql数据库导出为sql脚本&#xff0c;通过…...

(学习日记)2024.03.15:UCOSIII第十七节:任务的挂起和恢复

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…...

聚类分析 | Matlab实现基于NNMF+DBO+K-Medoids的数据聚类可视化

聚类分析 | Matlab实现基于NNMFDBOK-Medoids的数据聚类可视化 目录 聚类分析 | Matlab实现基于NNMFDBOK-Medoids的数据聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 NNMFDBOK-Medoids聚类&#xff0c;蜣螂优化算法DBO优化K-Medoids 非负矩阵分解&#xff08…...

Unity类银河恶魔城学习记录11-3 p105 Inventory UI源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_itemSlot.cs using System.Collections; using System.Collections.Gen…...

Vue3 + Vite + ts引入本地图片

Vue3 Vite ts引入本地图片 单张图片导入 单个图片导入&#xff0c;不过多阐述&#xff0c;通过 import 导入需要使用的图片。 import imgName from /assets/img/imgName.png 多张图片导入 new URL() import.meta.url import.meta.url 是一个 ESM 的原生功能&#xff0…...

图斑或者道路如何单独显示名称在图斑上或者道路上

0序&#xff1a; 遇到过多个测绘、工程、林业相关业务的客户&#xff0c;在加载一些图斑数据&#xff0c;线路数据时&#xff0c;希望能够单独的把图斑的名称&#xff0c;显示到图斑上&#xff0c;或者路网上面。 之前多数推荐的办法&#xff1a; 1.shp可以直接在图新地球中…...

docker 修改默认存储位置

一般系统下系统盘可能磁盘空间有限&#xff0c;需要将docker的存储目录改到其他位置 docker info 查看docker的版本 低版本docker在配置json中增加"graph":"/var/lib/docker" 高版本docker在配置json中增加"data-root":"/var/lib/docker&q…...

Springboot+vue的医疗挂号管理系统+数据库+报告+免费远程调试

效果介绍: Springbootvue的医疗挂号管理系统&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 本文设计了一个基于Springbootvue的前后端分离的医疗挂号管理系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;con…...

【Effective C++】39 明智而审慎地使用private继承

在之前论证过c如何将public 继承视为 is-a 关系。在哪个例子里&#xff0c;class Student 以 public 形式继承class Person&#xff0c; 于是编译器在必要时刻将Students暗自转化为Person.如果此时我们以 private 继承替换 public继承。 class Person {...}; class Student: p…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...

手动给中文分词和 直接用神经网络RNN做有什么区别

手动分词和基于神经网络&#xff08;如 RNN&#xff09;的自动分词在原理、实现方式和效果上有显著差异&#xff0c;以下是核心对比&#xff1a; 1. 实现原理对比 对比维度手动分词&#xff08;规则 / 词典驱动&#xff09;神经网络 RNN 分词&#xff08;数据驱动&#xff09…...

生信服务器 | 做生信为什么推荐使用Linux服务器?

原文链接&#xff1a;生信服务器 | 做生信为什么推荐使用Linux服务器&#xff1f; 一、 做生信为什么推荐使用服务器&#xff1f; 大家好&#xff0c;我是小杜。在做生信分析的同学&#xff0c;或是将接触学习生信分析的同学&#xff0c;<font style"color:rgb(53, 1…...

如何使用CodeRider插件在IDEA中生成代码

一、环境搭建与插件安装 1.1 环境准备 名称要求说明操作系统Windows 11JetBrains IDEIntelliJ IDEA 2025.1.1.1 (Community Edition)硬件配置推荐16GB内存50GB磁盘空间 1.2 插件安装流程 步骤1&#xff1a;市场安装 打开IDEA&#xff0c;进入File → Settings → Plugins搜…...