阅读 1506

从JSX到渲染页面,中间发生了什么😯【React Plan】

在这里插入图片描述

前言

最近在学习React过程中,对JSX的理解不是很清楚,只知道JSX是一种可以通过Bable转译成一个名为 React.createElement() 函数调用的JavaScript 语法扩展。还有为什么通过把一个 React 元素,和根 DOM 节点传入 ReactDOM.render(),就可以把这个React 元素渲染到根 DOM 节点中。小小的脑袋有大大的疑惑。

今天就来聊一下有关React中JSX写的东西如何从最开始浏览器不懂的语法,变身成为页面渲染的种子选手,从而在页面显示。

希望看完这篇文章的你也有所收获吧

在这里插入图片描述

✍️✍️✍️✍️✍️✍️✍️

首先来看看我们整篇文章的脉络:

在这里插入图片描述

1、JSX定义和使用

JSX 在react官方文档是这么定义的:

它被称为 JSX,是一个 JavaScript 的语法扩展。

好吧,这么直接说,有点子抽象。让我们先来看一段的代码:

<body>
  <div id="app"></div>
  //引入CDN 下面的代码都需要引入我就不一一注释啦
  <script type="text/babel">
    ReactDOM.render(
      <h2>hello</h2>,
      document.getElementById("app")
    )
  </script>
</body>
复制代码

我们通过ReactDOM.render()函数将<h2>hello</h2>元素渲染到根节点中,当然我们也可以这样:

   <script type="text/babel">
    const message = <h2>hello</h2>
    ReactDOM.render(
      message,
      document.getElementById("app")
    )
  </script>
复制代码

我们把<h2>hello</h2>提到函数外面去,使用定义的message代替,页面可以正常显示。 其中的这句代码就是我们说的JSX代码

const message = <h2>hello</h2>
复制代码

这个有趣的标签语法既不是字符串也不是 HTML。

注意这里有个小细节:就是我们这里的代码的script标签里都有一个type="text/babel",(当然在上面我们也引入了babel.min.js)如果没有这个属性,将会编译失败

在这里插入图片描述

这是因为我们的浏览器是不能直接识别JSX语法的,它必须通过Babel进行编译。

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。

下面让我们来介绍一下这个 React.createElement() 函数

2、JSX 是 React.createElement()的语法糖

下面两句代码的x显示效果是一样的,只不过一种是使用JSX语法,但是它通过Bable编译也会变成下面的这个样子。

const message = <h2>hello</h2> 
const message = React.createElement("h2",null,"hello");
复制代码

那既然两种方式都可以实现,为什么还要使用JSX语法,这样不是多了一步Babel编译吗?

事实是这样,连react官网都说React 不强制要求使用 JSX。但是,你看上面的代码是只有一行,所以两种方法没什么很大区别,当代码多了,一个标签内嵌套标签甚至多个标签,这里还不要说加组件了。很明显代码是非常多的,因为我们需要不断的调用React.createElement()方法。

让我们尝试写一个更复杂的代码,去理解:

render() {
       return (
         <div>
          <div className="head1">
            <h1>我是标题1</h1>
          </div>
          <div className="head1">
            <h2>我是标题2</h2>
          </div> 
          <div className="head3">
            <h3>我是标题1</h3>
          </div> 
         </div>
       )
     }
复制代码

我们可以来到Babel官网将上面的代码编译一下

Babel 官网

下面JSX代码通过Babel进行编译后的:

"use strict";
/*#__PURE__*/
React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
  className: "head1"
}, /*#__PURE__*/React.createElement("h1", null, "\u6211\u662F\u6807\u98981")), /*#__PURE__*/React.createElement("div", {
  className: "head1"
}, /*#__PURE__*/React.createElement("h2", null, "\u6211\u662F\u6807\u98982")), /*#__PURE__*/React.createElement("div", {
  className: "head3"
}, /*#__PURE__*/React.createElement("h3", null, "\u6211\u662F\u6807\u98981")));
复制代码

可以看到,Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用,(划重点,可以看到它的复杂性) 在我们刚才调用React.createElement中,这个函数接收三个参数

  • type

当前reactElement的类型 如果是标签元素,就使用"div" 如果是组件元素,就直接用组件的名称

  • config

所有jsx中的属性都在config中以对象的属性和值的形式存储

  • children

存放在标签中的内容,以children数组的方式进行存储 如果是多个元素

而实际上这个函数调用完后会返回一个对象:

这里截取了源码生成ReactElement对象的一小部分代码作为参考: 在这里插入图片描述

让我们打印看一下我们上面举的这个例子,也就是我们的ReactElement对象,长什么样:

在这里插入图片描述

到目前为止我们已经知道了,JSX语法的代码会通过Babel工具编译成一个名为 React.createElement() 函数调用,并且返回一个ReactElement对象,那么这个对象有什么用呢,它又是如何渲染到我们的页面?

3、如何从虚拟DOM树到渲染页面

你可能会奇怪,前面刚说到返回一个ReactElement对象,怎么就虚拟DOM树了。

在前端,用对象就可以表示一棵树了。不用怀疑,因为我们的html中DOM树就是这么来的: 在这里插入图片描述

在这里插入图片描述

上面我们返回的对象就是我们说的虚拟DOM树,想要渲染到根 DOM 节点中,只需传入 ReactDOM.render();

那么ReactDOM.render()又是如何将虚拟DOM树转换成真实DOM树呢?这也是我不懂的地方,个人觉得还不是很懂,还是要先去摸索摸索了。

总结

最后,我们来总结一下整篇文章

实际上JSX 是React.createElement(component,props,...children) 函数的语法糖,所有JSX最终都会转换成React.createElement的函数调用,

React.createElement函数返回的就是一个ReactElement对象,

这个对象就是我们所说的虚拟DOM,而这个虚拟DOM会通过ReactDOM.render()方法,挂载到我们同时传进去的根 DOM 节点中。

在这里插入图片描述

完💦💦💦

前端新人码字路过,肯定有不足或者写的不好的地方。欢迎大佬评论建议。万分感谢。