JSX底层渲染机制「创建virtualDOM」

308 阅读2分钟

1.关于JSX底层处理机制

第一步:把我们编写的JSX语法,编译为虚拟DOM对象「virtualDOM」

虚拟DOM对象:框架自己内部构建的一套对象体系(对象的相关成员都是React内部规定的),基于这些属性描述出,我们所构建视图中的,DOM节点的相关特征!!
    
我们可以在babel中实验一下

47E91EF55CC669F2E1DBD22A2F0988C5.png

左侧是输入编写的代码,右侧是babel编译过后的代码

我们把右侧编译过后的代码提炼出来看下

React.createElement(React.Fragment, null, 
React.createElement("h2", {
  className: "title",
  style: styleObj
}, 
"\u54C8\u54C8\u54C8\u54C8"), 
React.createElement("div", {
  className: "box"
}, 
React.createElement("span", null, "x"), 
React.createElement("span", null, "y")));
@1 基于 babel-preset-react-app 把JSX编译为 React.createElement(...) 这种格式!!

   只要是元素节点,必然会基于createElement进行处理!

   React.createElement(ele,props,...children)

    + ele:元素标签名「或组件」

    + props:元素的属性集合(对象)「如果没有设置过任何的属性,则此值是null」

    + children:第三个及以后的参数,都是当前元素的子节点
此时如果我们把createElement 方法执行结果打印出来看一下呢?
console.log(
    React.createElement(React.Fragment, null, 
    React.createElement("h2", {
      className: "title",
      style: styleObj
    }, 
    "\u54C8\u54C8\u54C8\u54C8"), 
    React.createElement("div", {
      className: "box"
    }, 
    React.createElement("span", null, "x"), 
    React.createElement("span", null, "y")));
)

YDC`FD_@(FEI6$70XBO0EBT.png 可以看到打印出来的就是虚拟DOM对象,是react内部构建出来的,里面包含了各种属性

    @2 再把 createElement 方法执行,创建出virtualDOM虚拟DOM对象「也有称之为:JSX元素、JSX对象、ReactChild对象...」!!

      virtualDOM = {

        $$typeof: Symbol(react.element),

        ref: null,

        key: null,

        type: 标签名「或组件」,

        // 存储了元素的相关属性 && 子节点信息

        props: {

            元素的相关属性,

            children:子节点信息「没有子节点则没有这个属性、属性值可能是一个值、也可能是一个数组」

        }

      }

第二步:把构建的virtualDOM渲染为真实DOM

    真实DOM:浏览器页面中,最后渲染出来,让用户看见的DOM元素!!

    基于ReactDOM中的render方法处理的!!

      v16

      ReactDOM.render(

        <>...</>,

        document.getElementById('root')

      );



      v18

      const root = ReactDOM.createRoot(document.getElementById('root'));

      root.render(

        <>...</>

      );

假如要我们自己来封装一下呢?

/* createElement:创建虚拟DOM对象 */

export function createElement(ele, props, ...children) {

    let virtualDOM = {

        $$typeof: Symbol('react.element'),

        key: null,

        ref: null,

        type: null,

        props: {}

    };

    let len = children.length;

    virtualDOM.type = ele;

    if (props !== null) {

        virtualDOM.props = {

            ...props

        };

    }

    if (len === 1) virtualDOM.props.children = children[0];

    if (len > 1) virtualDOM.props.children = children;

    return virtualDOM;

};

A1D8783419C57A97B572F8E1AE665EE8.png 补充说明:第一次渲染页面是直接从virtualDOM->真实DOM;但是后期视图更新的时候,需要经过一个DOM-DIFF的对比,计算出补丁包PATCH(两次视图差异的部分),把PATCH补丁包进行渲染!!

react中是通过胡子语法来渲染的,但是确不能直接在{}中填写对象,只有一下三种是可以直接渲染的

1.数组是可以直接渲染的;
2.标签中的style是可以在{}中直接填写对象名称的;
3.

5AFD5B7C306737C95D534AD080DC1C71.png