JSX 转换过程

294 阅读2分钟

1. 代码

render() {
        return (
          <div>
            <div className="header">Header</div>
            <div className="Conent">
              <div>Banner</div>
              <ul>
                <li>列表数据1</li>
                <li>列表数据2</li>
                <li>列表数据3</li>
                <li>列表数据4</li>
                <li>列表数据5</li>
              </ul>
            </div>
            <div className="footer"></div>
          </div>
        )
      }
    }

2. 大致过程

在 render 函数中写的 jsx 语法浏览器是不认识的,所以我们只有借助 Babel 工具,将我们写的 JSX 代码转化成浏览器能识别的代码,最终形成代码树,即虚拟DOM,如此才完成渲染。大致渲染过程可参考下面的图片:

image.png

3. 转化原理

实际上,JSX 仅仅只是 React.createElement(component,props,...children) 函数的语法糖。所有的 JSX 最终都会被转化为 React.createElement 函数的调用。

  • 参数一:type

    • 当前 ReactElement 的类型;
    • 如果是标签元素,就直接使用字符串表示;
    • 如果是组件元素,就直接使用组件元素的名称;
  • 参数二:config

    • 所有 JSX 中的属性都在 config 中以对象的属性和值的形式存储;
    • 比如传入 className 作为元素的 class;
  • 参数三:children

    • 存放在标签中的内容,以 children 数组的方式进行存储;
    • 如果是多个元素,React 内部有对它们进行处理;

4. babel 具体转化后的代码

render() {
        const element = React.createElement(
          "div",
          null,
  /*#__PURE__*/ React.createElement(
            "div",
            {
              className: "header"
            },
            "Header"
          ),
  /*#__PURE__*/ React.createElement(
            "div",
            {
              className: "Conent"
            },
    /*#__PURE__*/ React.createElement("div", null, "Banner"),
    /*#__PURE__*/ React.createElement(
              "ul",
              null,
      /*#__PURE__*/ React.createElement(
                "li",
                null,
                "\u5217\u8868\u6570\u636E1"
              ),
      /*#__PURE__*/ React.createElement(
                "li",
                null,
                "\u5217\u8868\u6570\u636E2"
              ),
      /*#__PURE__*/ React.createElement(
                "li",
                null,
                "\u5217\u8868\u6570\u636E3"
              ),
      /*#__PURE__*/ React.createElement(
                "li",
                null,
                "\u5217\u8868\u6570\u636E4"
              ),
      /*#__PURE__*/ React.createElement("li", null, "\u5217\u8868\u6570\u636E5")
            )
          ),
  /*#__PURE__*/ React.createElement("div", {
            className: "footer"
          })
        );

        return element
      }
      
    ...
    ...
    ...
    
    const root = ReactDOM.createRoot(document.querySelector('#root'))
    root.render(React.createElement(App, null))

5. 虚拟DOM

5.1 渲染虚拟 DOM 原理

本质上是将 JSX 代码转化为 ReactElement 对象,进而被解析成真实 DOM 节点,从而在浏览器上进行渲染。

5.2 声明式编程

虚拟 DOM 帮助我们从命名式编程转成了声明式编程的模式(React 官方说法:Virtual DOM 是一种编程理念)。

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

5.3 虚拟 DOM的作用

  • 在元素发生改变的时候,使用 diff 算法,仅对发生变化的元素进行替换,没发生变化的元素不做改变;
  • 跨平台开发。虚拟 DOM 的本质是一个 js 对象,所以可以在不同的端进行渲染,比如在 web端渲染成 div、button;在 iOS/Android 控件渲染成 UIView、UIButton。