首页 > 其他分享 >JSX 代码是如何“摇身一变”成为 DOM 的?

JSX 代码是如何“摇身一变”成为 DOM 的?

时间:2023-12-05 11:15:36浏览次数:26  
标签:render DOM JavaScript React 摇身一变 createElement JSX

JSX 是一种语法,并不是 React 中的内容,时下接入 JSX 语法的框架越来越多,但与之缘分最深的仍然是 React。本节来讲一下 React 是如何摇身一变成为 DOM 的。

我们平时在写React时会用 JSX 来描述组件的内容,例如下面的代码中,render 方法 return 的内容就是 JSX 代码。

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <h1 className="title">I am the title</h1>
        <p className="content">I am the content</p>
      </div>
    );
  }
}

我们考虑以下三个问题:

  1. JSX 的本质是什么,它和 JS 之间到底是什么关系?
  2. React 为什么要用 JSX?
  3. JSX 是如何映射为 DOM 的?

这一节我们就将这三个问题一一解答。

1)JSX 的本质是什么?它和JS之间的到底是什么关系?

JSX 到底是什么,我们先来看看 React 官网给出的一段定义:

JSX 是 JavaScript 的一种语法扩展,它和模板语言很接近,但是它充分具备 JavaScript 的能力。

“语法扩展”这一点在理解上几乎不会产生歧义,不过“它充分具备 JavaScript 的能力”这句,却总让人摸不着头脑,JSX 和 JS 怎么看也不像是一路人啊?这就引出了“JSX 语法是如何在 JavaScript 中生效的”这个问题。

JSX 是 JavaScript 的扩展,而不是 JavaScript 的某个版本,因此浏览器并不会天然支持,那么 JSX 是如何在 JavaScript 中生效的呢?

React 官网是这样的解释的:

JSX 会被编译为 React.createElement(), React.createElement() 将返回一个叫作“React Element”的 JS 对象。

那么 JSX 如何转换成 React.createElement() 的呢?答案就是通过 babel 转换。

我们直接打开 babel playground 来写一段 JSX 代码看一下 babel 转换后的结果。![image-20231204112041472](/Users/jiuyuezhang/Library/Application Support/typora-user-images/image-20231204112041472.png)

可以看到 JSX 代码都被转换成了 React.createElement 调用。

接下来我们总结一下来回答标题提到的两个问题。

JSX 是 JavaScript 的扩展,不是 JavaScipt 的某个版本,需要通过 Babel 进行转换成 JavaScript 代码。

JSX 会被 babel 转换为 React.CreateElement(...) 调用的形式,执行后返回的结果是一个对象。

2)React 为什么要用 JSX?

从上一节我们知道 JSX 等价于一次 React.createElement 调用,那么 React 官方为什么不直接引导我们用 React.createElement 来创建元素呢?

在实际功能效果一致的前提下,JSX 代码层次分明、嵌套关系清晰;而 React.createElement 代码则给人一种非常混乱的“杂糅感”,这样的代码不仅读起来不友好,写起来也费劲。

JSX 语法糖允许前端开发者使用我们最为熟悉的类 HTML 标签语法来创建虚拟 DOM,在降低学习成本的同时,也提升了研发效率与研发体验。

3)JSX 是如何映射为 DOM 的?

我们知道 JSX 经过babel转换后会变成 React.createElement(...) 的形式,接下来我们就来一起探讨一下 React.createElement(...) 是如何工作的?

3.1 入参解读:创造一个元素需要知道哪些信息

我们先来看看方法的入参:

export function createElement(type, config, children)

createElement 有 3 个入参,这 3 个入参囊括了 React 创建一个元素所需要知道的全部信息。

  • type:用于标识节点的类型。它可以是类似“h1”“div”这样的标准 HTML 标签字符串,也可以是 React 组件类型或 React fragment 类型。
  • config:以对象形式传入,组件所有的属性都会以键值对的形式存储在 config 对象中。
  • children:子节点,如果有多个子节点,那么依次往后写。

举个例子:

<ul className="list">
  <li key="1">1</li>
  <li key="2">2</li>
</ul>

经过 Babel 转换后的形式为:

注意:从第三个入参开始往后,传入的参数都是 children

React.createElement("ul", {
  // 传入属性键值对
  className: "list"
}, React.createElement("li", {
  key: "1"
}, "1"), React.createElement("li", {
  key: "2"
}, "2"));

3.2 出参解读:初识虚拟DOM

下面的代码是 React.createElement(...) 调用的返回值格式。

注意:这是 fiber节点之前的每个节点的格式。

const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // REACT_ELEMENT_TYPE是一个常量,用来标识该对象是一个ReactElement
    $$typeof: REACT_ELEMENT_TYPE,

    // 内置属性赋值
    type: type,
    key: key,
    ref: ref,
    props: props,

    // 记录创造该元素的组件
    _owner: owner,
  };

  // 
  if (__DEV__) {
    // 这里是一些针对 __DEV__ 环境下的处理,对于大家理解主要逻辑意义不大,此处我直接省略掉,以免混淆视听
  }

  return element;
};

举个例子

const AppJSX = (<div className="App">

  <h1 className="title">I am the title</h1>

  <p className="content">I am the content</p>

</div>)

console.log(AppJSX)

输出为:

这个 ReactElement 对象实例,本质上是以 JavaScript 对象形式存在的对 DOM 的描述,也就是老生常谈的“虚拟 DOM”(准确地说,是虚拟 DOM 中的一个节点

既然是“虚拟 DOM”,那就意味着和渲染到页面上的真实 DOM 之间还有一些距离,这个“距离”,就是由大家喜闻乐见的ReactDOM.render方法来填补的。

在每一个 React 项目的入口文件中,都少不了对 React.render 函数的调用。下面我简单介绍下 ReactDOM.render 方法的入参规则:

复制代码

ReactDOM.render(
    // 需要渲染的元素(ReactElement)
    element, 
    // 元素挂载的目标容器(一个真实DOM)
    container,
    // 回调函数,可选参数,可以用来处理渲染结束后的逻辑
    [callback]
)

ReactDOM.render 方法可以接收 3 个参数,其中第二个参数就是一个真实的 DOM 节点这个真实的 DOM 节点充当“容器”的角色,React 元素最终会被渲染到这个“容器”里面去。比如,示例中的 App 组件,它对应的 render 调用是这样的:

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

注意,这个真实 DOM 一定是确实存在的。比如,在 App 组件对应的 index.html 中,已经提前预置 了 id 为 root 的根节点:

<body>
    <div id="root"></div>
</body>

标签:render,DOM,JavaScript,React,摇身一变,createElement,JSX
From: https://www.cnblogs.com/zhangguicheng/p/17876753.html

相关文章

  • JS的DOM操作一:DOM操作简介
    DOM操作简介只编写HTML而产生的页面是静态的(静态页面),是没办法和它进行交互,例如点击按钮,提交表单等。JavaScript语言,就是专门为HTML页面添加交互。(使用JS编写相关代码,将页面由静转动,也就是动态页面)【PS:爬虫的时候最不喜欢的就是动态页面了(doge)要动脑】为了能在JavaScript直......
  • 本地套接字domain的使用
    socketAPI原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIXDomainSocket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIXDomainSocket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和......
  • Tightly Secure Lattice Identity-Based Signature in the Quantum Random Oracle Mod
    Abstract.Wepresentaquantumlysecureidentity-basedsignatureschemebasedonthestandardshortintegersolutionproblem,featuringtightsecurityreductionsinthequantumandclassicrandomoraclemodels.Theschemehasshortsignatures.Eachsignat......
  • Vulnhub DomDom-1(靶机玩乐2023-11-30)
    靶机下载地址:https://www.vulnhub.com/entry/domdom-1,328/第一步:扫一下同网段接口IP: 第二步:nmap扫描版本端口详细信息并输出  第三步:访问80端口服务 第四步:简单做做dirb目录遍历,也可以安装gobuster等做目录扫描:https://blog.csdn.net/qq_22597955/article/details......
  • FPGA入门笔记007_A——按键消抖模块设计与验证(状态机、$random、仿真模型、task语法)
    实验现象:每次按下按键0,4个LED显示状态以二进制加法格式加1。每次按下按键1,4个LED显示状态以二进制加法格式减1。知识点:1、testbench中随机数发生函数$random的使用;2、仿真模型的概念1、按键波形分析:按键未按,FPGA管脚检测到高电平。按键按下,FPGA管脚检测到低电平。2、设......
  • C++随机数random库 介绍及应用
    一、摘要随机数可以应用在很多场景下如游戏抽卡、抽奖、场景生成、洗牌,歌曲app中的随机播放,社交app中的匹配等以及随机化算法。以下是针对C中随机函数rand、C++random库使用的总结,以及一些随机应用例子二、C/C++中的rand函数使用时需要引入头文件<stdlib.h>该函数返回一个......
  • java基础学习:random随机数,random案例
    1.Random使用步骤:  packagecom.itheima.Random;importjava.util.Random;publicclassRandom1{publicstaticvoidmain(String[]args){Randomrandom=newRandom();for(inti=1;i<=10;i++){intdata=random.nextInt(1......
  • Ant-Design modal对话框未打开时,无法通过uesRef获取modal内部元素DOM节点
    为什么要记录下来呢?因为我在网上和chatGpt上没有搜到合适的解决方案。在CDNS上看到个和我遇到问题一样的,居然要收费才能看,所以自己记下来。当然肯定还有其他的好方案,欢迎大家留言。需求:使用antdV/g6画关系图,类似于企查查上面的那样:点击按钮打开Modal框,把数据渲染到Modal框的div......
  • [ABC277G] Random Walk to Millionaire 题解
    题目链接点击打开链接题目解法首先\(O(n^3)\)的\(dp\)是显然的,令\(f_{i,j,k}\)为第\(i\)步在\(j\),当前等级为\(k\)的\([i,n]\)步获得钱数的期望,转移枚举出边即可一个很妙的优化是:贡献都是\(k^2\)的形式,所以我们考虑维护\(k\)的\(0,1,2\)次幂,即\(\sum,\sum......
  • 学习Vue3 第五章(Vue核心虚拟Dom和 diff 算法)
      介绍虚拟DOM虚拟DOM就是通过JS来生成一个AST节点树   为什么要有虚拟DOM?一个dom上面的属性是非常多的,所以直接操作DOM非常浪费性能介绍Diff算法diff算法的目的就是找出新旧不同虚拟DOM之间的差异,使最小化的更新视图,所以diff算法本质上就是......