Skip to content
On this page

关于 JSX 底层处理机制

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

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

基于 babel-preset-react-app 把 JSX 编译为 React.createElement(...) 这种格式!!

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

React.createElement(ele,props,...children) + ele:元素标签名「或组件」 + props:元素的属性集合(对象)「如果没有设置过任何的属性,则此值是 null」 + children:第三个及以后的参数,都是当前元素的子节点

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

javaScript
virtualDOM = {
  $$typeof: Symbol(react.element),
  ref: null,
  key: null,
  type: 标签名「或组件」,
  // 存储了元素的相关属性 && 子节点信息
  props: {
    //   元素的相关属性,
    children: "子节点信息「没有子节点则没有这个属性、属性值可能是一个值、也可能是一个数组」"
  }
}
1
2
3
4
5
6
7
8
9
10
11

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

真实 DOM:浏览器页面中,最后渲染出来,让用户看见的 DOM 元素!! 基于 ReactDOM 中的 render 方法处理的!!

v16

javascript
ReactDOM.render(<>...</>, document.getElementById("root"));
1

v18

javascript
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<>...</>);
1
2

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

createElement

javascript
const createElement = function createElement(type, props, ...children) {
    // virtual:[ˈvɜːtʃuəl]
    let len = children.length;
    let virtualDOM = {
        type,
        props: {}
    };
    if (props !== null) virtualDOM.props = { ...props };
    if (len === 1) virtualDOM.props.children = children[0];
    if (len > 1) virtualDOM.props.children = children;
    return virtualDOM;
};
1
2
3
4
5
6
7
8
9
10
11
12

render

javascript
const render = function render(virtualDOM, container) {
    let { type, props } = virtualDOM;
    if (typeof type === "string") {
        let element = document.createElement(type);
        for (let key in props) {
            if (!props.hasOwnProperty(key)) break;
            if (key === 'className') {
                element.setAttribute('class', props[key]);
                continue;
            }
            if (key === 'style') {
                let styOBJ = props['style'];
                for (let attr in styOBJ) {
                    if (!styOBJ.hasOwnProperty(attr)) break;
                    element.style[attr] = styOBJ[attr];
                }
                continue;
            }
            if (key === 'children') {
                let children = props['children'];
                if (!Array.isArray(children)) children = [children];
                children.forEach(item => {
                    if (typeof item === "string") {
                        element.appendChild(document.createTextNode(item));
                        return;
                    }
                    render(item, element);
                });
                continue;
            }
            element.setAttribute(key, props[key]);
        }
        container.appendChild(element);
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
沪ICP备20006251号-1