实际上JSX只是React.createElement(component,props,children)函数的语法糖。

1.什么是语法糖?

如果写React.createElement这种太复杂了,我们就延伸出了一种简单的方法,就是说我们写JSX更简单效果却和写React.createElement一样,我们在里面尝到了甜头,可以称为这个函数的语法糖。

JSX最终都会被转换成React.createElement函数的调用。

通过什么转换的?通过babel,如果是写jsx语法,script标签type也要设置成type="text/babel"否则它不会识别JSX语法。

2.查看React.createElement源码

JSX的本质(3)

JSX的本质(3)

createElement需要传递三个参数:

参数一:type

  • 当前ReactElement的类型;
  • 如果是标签元素,那么就使用字符串表示 “div”;
  • 如果是组件元素,那么就直接使用组件的名称;

参数二:config

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

参数三:children

  • 存放在标签中的内容,以children数组的方式进行存储;
3.babel官网查看jsx转换的createElement

babel官网:babeljs.io

JSX的本质(3)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
  <script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

  <script type="text/babel">
    class App extends React.Component {
      constructor() {
        super();

      }

      render() {
        return/*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
          className: "header"
        }, /*#__PURE__*/React.createElement("h2", null, "\u6211\u662F\u5934\u90E8")), /*#__PURE__*/React.createElement("div", {
          className: "content"
        }, /*#__PURE__*/React.createElement("h2", null, "\u6211\u662F\u9875\u9762\u7684\u5185\u5BB9"), /*#__PURE__*/React.createElement("button", null, "-1"), /*#__PURE__*/React.createElement("button", null, "+1"), /*#__PURE__*/React.createElement("a", {
          href: "www.baidu.com"
        }, "\u767E\u5EA6")), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("p", null, "\u6211\u662F\u5E95\u90E8")));
      }
    }

    ReactDOM.render(<App />, document.getElementById("app"));
  </script>
</body>
</html>
4.虚拟DOM的创建过程

我们会发现最终React.createElement返回(创建)了一个ReactElement对象

JSX的本质(3)

而ReactElement最终形成的树结构就是Virtual DOM;

最后使用ReactDOM.render()映射虚拟DOM-》浏览器真实DOM

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
  <script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

  <script type="text/babel">

    class App extends React.Component {
      constructor() {
        super();

      }

      render() {
  // jsx -> babel -> React.createElement -> ReactElement(对象树) -> React.render() -> 真实DOM
        let ReactElementObj = <div>
          <div className="header">
            <h2>我是头部</h2>
          </div>
          <div className="content">
            <h2>我是页面的内容</h2>
            <button>-1</button>
            <button>+1</button>
            <a href="www.baidu.com">百度</a>
          </div>
          <div>
            <p>我是底部</p>
          </div>
        </div>;

        console.log(ReactElementObj);
        return ReactElementObj;
      }
    }
    ReactDOM.render(<App />, document.getElementById("app"));
  </script>
</body>
</html>

jsx -> babel -> React.createElement -> ReactElement(对象树) -> React.render() -> 真实DOM

5.为什么使用虚拟DOM?

为什么使用虚拟DOM而不是直接修改真实DOM呢?

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

DOM操作性能非常低:

  • 首先,document.createElement本身创建出来的就是一个非常复杂的对象。
  • 其次,DOM操作会引起浏览器的回流和重绘,所以在开发中应该避免频繁的DOM操作。

举个例子,需要渲染5个li,如果使用原生js来操作dom是一次一次的添加的进行了多次的DOM操作。

对于上面的问题,虚拟DOM就可以帮我们解决这个问题,虚拟DOM帮助我们从命令式编程转到了声明式编程的模式。

  • React官方的说法:Virtual DOM 是一种编程理念

    • 在这个理念中,UI以一种理想化或者说虚拟化的方式保存在内存中,并且它是一个相对简单的JavaScript对象
    • 我们可以通过ReactDOM.render让 虚拟DOM 和 真实DOM同步起来,这个过程中叫做协调(Reconciliation)

React设计原则: state中数据的不可变性

文章目录