React中的jsx语法转换后生成虚拟DOM,再挂载到真实的DOM中的全过程讲解

530 阅读4分钟

前言

react中的jsx语法很多伙伴都会使用,但是你知道它的本质是什么吗?运行中它会做如何的转换呢?jsx内部又是怎么生成了虚拟DOM?虚拟DOM又是如何挂载到真实DOM上去的呢?带着这些问题,我们做个讲解把,相信深度了解本文后,肯定会jsx、虚拟DOM有进一步的理解

1、react中的jsx语法

  • 1.1 这就是简单的jsx语法, 就是再js中写html元素,前提是script标签必须加 type=text/babel, 否则jsx语法会报错

    Snipaste_2022-04-17_09-27-36.png

2、jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖

const msg1 = <h2>哈哈哈</h2>
  • 2.1 在js中上面这段代码等价于下面这段react.createElement()的值
const msg2 = React.createElement("h2", null, "哈哈哈");//js语法
  • 2.2 jsx语法在babel中会转成 React.createElement()的函数调用。 注意:使用了React相关的方法一定先引入react.development.js 和 react-dom.development.js 这两个文件,否则会报错
<script src="../react/react.development.js"></script>
<script src="../react/react-dom.development.js"></script>

3、babel转换

  • 3.1 我们先用jsx语法, 开发页面。部分html代码省略,只写核心js代码
<script src="../react/react.development.js"></script>
<script src="../react/react-dom.development.js"></script>
//babel.min文件 是将 jsx转成 React.createElement函数调用的
<script src="../react/babel.min.js"></script>
<script type='text/babel'>
// 这是jsx语法
const msg1 = 
   <div class="header">
     <h2>头部</h2>
     <div class="main">主题</div>
     <footer>这里是尾部</footer>
   </div>;
   
ReactDOM.render(msg1, document.getElementById("app"));
</script>
  • 用浏览器打开文件,查看页面效果

Snipaste_2022-04-17_09-33-01.png

  • 3.2 然后我们在把上面的jsx代码转成 React.createElement函数的形式
  • 3.3 可以在babel的官网中快速查看转换的过程。babel官网链接: babeljs.io/repl/#?pres…

Snipaste_2022-04-17_09-34-19.png

  • 3.4 复制右边转换后的React.createElement函数调用代码到js中
<script src="../react/react.development.js"></script>
<script src="../react/react-dom.development.js"></script>
// type="text/babel" 可以去掉,babel.min.js 也可以不用了。
// 因为我们代码中没有了jsx语法了。下面的代码属于正常的js代码
<script>
const msg2 = React.createElement("div", {
   	class: "header"
}, React.createElement("h2", null, "\u5934\u90E8"), React.createElement("div", {
    class: "main"
}, "\u4E3B\u9898"), React.createElement("footer", null, "\u8FD9\u91CC\u662F\u5C3E\u90E8"));
//React.reder 函数渲染到浏览器上
ReactDOM.render(msg2, document.getElementById("app"));
</script>

在浏览器中打开后,查看页面

Snipaste_2022-04-17_09-35-47.png

  • 3.6 jsx语法和React.createElement函数的方法都可以得到相同的结果,渲染在页面的正是DOM也是一样的。
  • 3.7 所以我们可以得出结论:jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖
  • 3.8 在真实开发中我们不会使用React.createElement函数的方式写代码,因为可读性太差了,代码量又多,难维护,我们更喜欢使用jsx语法来编写代码
  • 3.9 React.render函数是怎样把createElement函数的返回值挂载到DOM上的呢?

4、虚拟DOM的创建过程

  • 4.1 React.createElement 最终创建出来一个 ReactElement对象
  • 4.1.1 在上面的React.createElement函数调用后,打印它的返回值
const msg2 = React.createElement("div", {
    class: "header"
 },React.createElement("h2", null, "\u5934\u90E8"), React.createElement("div", {
    class: "main"
 }, "\u4E3B\u9898"), React.createElement("footer", null, "\u8FD9\u91CC\u662F\u5C3E\u90E8"));

console.log(msg2);
ReactDOM.render(msg2, document.getElementById("app"));

在浏览器打开,查看结果

Snipaste_2022-04-17_09-36-33.png

msg2就是一个object对象,对象的第一层是html中的最外层class等于header的div。div里面的三个子元素,放在对象中的props对象中的children数组中一一对应。如果h2标签中还有子元素,那h2对象中的props对象中的children数组又会有objectd对象,...... 这将一层一层的往下套

  • 4.2 是React利用ReactElement对象组成了一个JavaScript的对象树
    • 4.2.1 msg2就是调用React.createElement函数时候,通过ReactElement函数转成一个JavaScript对象树的

    • 4.2.2 有兴趣的伙伴可以去读一下react的源码。在这我就粗略的分享一下我读react源码

    • 4.2.3 在react源码下/packages/react/index.js文件找到了createElement函数,它是 ./src/React文件下导出的

      Snipaste_2022-04-17_09-37-27.png

    • 4.2.4 找到react文件,发现它是 ./ReactElement文件下导出的

      Snipaste_2022-04-17_09-37-54.png

    • 4.2.5 找到ReactElement文件,里面有一个createElement函数,在js中本质上就是在调用这个函数

      Snipaste_2022-04-17_09-38-27.png

      Snipaste_2022-04-17_09-38-54.png

    • 4.2.6 它又调用了另一个ReactElement函数

      Snipaste_2022-04-17_09-39-25.png

      Snipaste_2022-04-17_09-39-57.png

    • 4.2.7 这个ReactElement函数返回是一个object对象,这个对象就是我们在浏览器打印出来的那个msg2, 它就是javascript对象树

  • 4.3 JavaScript的对象树就是大名鼎鼎的虚拟DOM
    • 4.3.1 有了虚拟DOM,那怎么把虚拟DOM映射到真实的DOM上呢?
    • 4.3.2 react是通过ReactDOM.render 函数把虚拟DOM挂载到真实DOM的
//把虚拟DOM挂载到 id为app的元素中
ReactDOM.render(msg2, document.getElementById("app"));

Snipaste_2022-04-17_09-40-34.png

5、为什么要使用虚拟DOM

  • 5.1 很难跟踪状态发生的改变:原有的开发模式,我们很难跟踪到状态发生的改变,不方便针对我们应用程序进行调试
  • 5.2 操作真实DOM性能较低:传统的开发模式会进行频繁的DOM操作,而这一的做法性能非常的低

有关react中的jsx到虚拟DOM的分享就到这里,如有问题,欢迎留言!谢谢大家