Appearance
关于 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
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
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
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
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