react基础(四)

126 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

前言

大家好呀, 我是L同学。在上篇文章react基础(三)中,我们学习了如何在事件中传递参数,进行条件渲染,列表渲染等内容。学习了基本使用,接下来在这篇文章中,我们将学习jsx的本质,虚拟DOM等内容。

jsx的本质

我们先看一下jsx的基本使用。

<body>
  <div id="app"></div>

  <script src="../react/react.development.js"></script>
  <script src="../react/react-dom.development.js"></script>
  <script src="../react/babel.min.js"></script>
  
  <script type="text/babel">
    const message = <h2>hello react</h2>

    ReactDOM.render(message, document.getElementById('app'))

  </script>
</body>

所有的jsx都会借助babel最终转换成React.createElement函数调用。所以说,jsx是React.createElement(component, props, ...children)函数的语法糖

其中,React.createElement需要传递三个参数。

第一个参数: type。也就是当前ReactElement的类型。如果是标签元素,那么就是用字符串表示。在上面例子中,用'h2'这个字符串表示。如果是组件,那么就直接使用组件的名字。

第二个参数: config。在html元素中可以添加属性。所有在jsx中的属性都在config中以对象的属性和值的形式进行存储。

第三个参数: children。存放在标签中的内容,以children数组的方式进行存储。

上面说过,jsx最终会被babel转换为React.createElement的函数调用。我们可以在babel官网测试下。

image.png 我们可以在图中看到我们写得jsx代码最终做了转换。

那么我们接下来再做测试。我们不写jsx代码,直接写经过babel转换后的代码,会有问题吗?

此时我们就不需要babel了,把babel引入和type="text/babel"删掉。

<body>
  <div id="app"></div>

  <script src="../react/react.development.js"></script>
  <script src="../react/react-dom.development.js"></script>
  <!-- <script src="../react/babel.min.js"></script> -->

  <script>
    // const message = <h2>hello react</h2>
    const message = React.createElement("h2", null, "hello react")

    ReactDOM.render(message, document.getElementById('app'))

  </script>
</body>

我们可以看到内容可以正常显示到页面上。 image.png

接下来我们来测试下组件的情况。

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

      render() {
        return (
          <div>
            <div className='header'>
              <h1 title='标题'>我是标题</h1>
            </div>

            <div className='content'>
              <h2>我是页面的内容</h2>
              <button>按钮</button>
              <button>+1</button>
            </div>

            <div className='footer'>
              <p>我是尾部内容</p>
            </div>

          </div>
        )
      }
    }

    ReactDOM.render(<App />, document.getElementById('app'))
  </script>

页面内容可以正常显示。

image.png 然后我们将babel转换后的代码放到render函数中。

image.png

<body>
  <div id="app"></div>
  <script src="../react/react.development.js"></script>
  <script src="../react/react-dom.development.js"></script>
  <script src="../react/babel.min.js"></script>

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

        }
      }

      render() {
        return /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
          className: "header"
        }, /*#__PURE__*/React.createElement("h1", {
          title: "\u6807\u9898"
        }, "\u6211\u662F\u6807\u9898")), /*#__PURE__*/React.createElement("div", {
          className: "content"
        }, /*#__PURE__*/React.createElement("h2", null, "\u6211\u662F\u9875\u9762\u7684\u5185\u5BB9"), /*#__PURE__*/React.createElement("button", null, "\u6309\u94AE"), /*#__PURE__*/React.createElement("button", null, "+1")), /*#__PURE__*/React.createElement("div", {
          className: "footer"
        }, /*#__PURE__*/React.createElement("p", null, "\u6211\u662F\u5C3E\u90E8\u5185\u5BB9")));
      }
    }

    ReactDOM.render(<App/>, document.getElementById('app'))
  </script>
</body>

我们可以看到页面还是可以正常的显示。

image.png

总结一下,所有的jsx都会借助babel最终转换成React.createElement函数调用。所以说,jsx是React.createElement(component, props, ...children)函数的语法糖

虚拟DOM的创建过程

我们知道,jsx最终会被转换为React.createElement函数。然后React.createElment会创建出来ReactElement对象。react会利用ReactElement对象组建一个javascript对象树,也就是虚拟DOM

我们可以把jsx返回的结果打印出来。

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

        }
      }

      render() {
        var elementObj = (
          <div>
            <div className='header'>
              <h1 title='标题'>我是标题</h1>
            </div>

            <div className='content'>
              <h2>我是页面的内容</h2>
              <button>按钮</button>
              <button>+1</button>
            </div>

            <div className='footer'>
              <p>我是尾部内容</p>
            </div>

          </div>
        )

        console.log(elementObj);
        return elementObj
      }
    }

    ReactDOM.render(<App/>, document.getElementById('app'))
  </script>

image.png 那么有了虚拟DOM,那么如何将虚拟DOM转换为真实DOM最终渲染到页面上呢?

实际上,ReactDOM.render函数会将虚拟DOM转换为真实DOM。

我们来总结下整个流程。

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

使用虚拟DOM的原因

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

这是因为真实DOM,一方面很难跟踪状态发生改变,另一方面,操作真实DOM性能较低。