前言
react
中的jsx
语法很多伙伴都会使用,
- 但是你知道它的本质是什么吗?运行中它会做如何的转换呢?
jsx
内部又是怎么生成了虚拟DOM
?- 虚拟
DOM
又是如何挂载到真实DOM
上去的呢?
带着这些问题,我们做个讲解把,相信深度了解本文后,肯定会jsx
、虚拟DOM
有进一步的理解
1、react中的jsx语法
-
简单的
jsx
语法, 就是再js
中写html
元素,前提是script
标签必须加type=text/babel
, 否则jsx
语法会报错
-
jsx
仅仅只是React.createElement(component, props, ...children)
函数的语法糖const msg1 = <h2>哈哈哈</h2>
在
js
中上面这段代码等价于下面这段react.createElement()的值const msg2 = React.createElement("h2", null, "哈哈哈");//js语法
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转换
-
我们先用
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>
用浏览器打开文件,查看页面效果
-
然后我们在把上面的
jsx
代码转成React.createElement
函数的形式 -
可以在
babel
的官网中快速查看转换的过程。babel
官网链接:https://babeljs.io/repl/#?presets=react
-
复制右边转换后的
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>
在浏览器中打开后,查看页面
-
jsx
语法和React.createElement
函数的方法都可以得到相同的结果,渲染在页面的正是DOM
也是一样的。 -
所以我们可以得出结论:
jsx
仅仅只是React.createElement(component, props, ...children)
函数的语法糖 -
在真实开发中我们不会使用
React.createElement
函数的方式写代码,因为可读性太差了,代码量又多,难维护,我们更喜欢使用jsx
语法来编写代码 -
React.render
函数是怎样把createElement
函数的返回值挂载到DOM
上的呢?
4、虚拟DOM的创建过程
-
React.createElement
最终创建出来一个ReactElement
对象-
在上面的
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"));
在浏览器打开,查看结果
msg2
就是一个object
对象,对象的第一层是html
中的最外层class
等于header
的div
。div
里面的三个子元素,放在对象中的props
对象中的children
数组中一一对应。如果h2
标签中还有子元素,那h2
对象中的props
对象中的children
数组又会有objectd
对象,… 这将一层一层的往下套
-
-
React
利用ReactElement
对象组成了一个JavaScript
的对象树-
msg2
就是调用React.createElement
函数时候,通过ReactElement
函数转成一个JavaScript
对象树的 -
在
react
源码下/packages/react/index.js
文件找到了createElement
函数,它是./src/React
文件下导出的
-
找到
react
文件,发现它是./ReactElement
文件下导出的 -
找到
ReactElement
文件,里面有一个createElement
函数,在js中本质上就是在调用这个函数
-
它又调用了另一个
ReactElement
函数 -
这个
ReactElement
函数返回是一个object
对象,这个对象就是我们在浏览器打印出来的那个msg2
, 它就是javascript
对象树
-
-
JavaScript
的对象树就是大名鼎鼎的虚拟DOM
-
有了虚拟
DOM
,那怎么把虚拟DOM
映射到真实的DOM
上呢? -
react
是通过ReactDOM.render
函数把虚拟DOM
挂载到真实DOM
的//把虚拟DOM挂载到 id为app的元素中 ReactDOM.render(msg2, document.getElementById("app"));
-
5、为什么要使用虚拟DOM
- 很难跟踪状态发生的改变:原有的开发模式,我们很难跟踪到状态发生的改变,不方便针对我们应用程序进行调试
- 操作真实
DOM
性能较低:传统的开发模式会进行频繁的DOM
操作,而这一的做法性能非常的低