Virtual DOM
Virtual DOM
的主要思想就是模拟 DOM
的树状结构,在内存中创建保存映射 DOM
信息的节点数据,在由于交互等因素需要视图更新时,先通过对节点数据进行 diff
后得到差异结果后,再一次性对DOM
进行批量更新操作,这就好比在内存中创建了一个平行世界,浏览器中 DOM
树的每一个节点与属性数据都在这个平行世界中存在着另一个版本的虚拟 DOM
树,所有复杂曲折的更新逻辑都在平行世界中的 Virtual DOM
处理完成,只将最终的更新结果发送给浏览器中的 DOM
树执行,这样就避免了冗余琐碎的 DOM
树操作负担,进而有效提高了性能。
React 中的 Virtual DOM
React
实际是通过 React.createElement
创建 JavaScript
对象 (Virtual DOM
) 来模拟 DOM
的树状结构
<div>
Virtual DOM
</div>
被转换过后的对象如下:
源码解析
ps. 下述代码均为简化后的源码,看起来方便点
主要就是看 createElement
方法是如何将元素转换为对应的 js
对象
React.createElement(
"div",
{className: 'test'},
"1"
)
createElement
的入参
type
:类型参数,可以是HTML
元素(<div>
等),也可以是React
组件类型props
:props
入参children
: 子元素,从第三个参数开始传入的参数都是子元素
createElement
的处理流程
-
处理入参,props
- 将
ref
、key
从 props 中剥离出来(这就是为什么子组件props
中取不到ref
、key
) - 将
__self
、__source
从props
中剥离出来
var key = null; var ref = null; var source = null; var self = null; // 将 props 中的 ref、key、__self、__source 剥离出来 if (props !== null) { if (props.ref) { ref = props.ref props.delete(ref); } if (props.key) { key = '' + props.key; props.delete(key); } if(props.__self) { self = props.__self; props.delete(__self); } if(props.__source) { self = props.__source; props.delete(__source); } }
- 将
-
处理入参,children
- 在
props
对象上添加children
属性,其值就是入参children
- 如果有多个
children
入参的话,则合并成一个数组
// 将所有子元素整合到 props.children var childrenLength = arguments.length - 2; if (childrenLength === 1) { // 只有一个子元素 props.children = children; } else if (childrenLength > 1) { // 多个子元素,合并成一个数组 var childArray = Array(childrenLength); for (var i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } Object.freeze(childArray); props.children = childArray; }
- 在
-
处理
class
组件上的defaultProps
- 组件默认的
props
- 如果
props
上没有对应属性的话,则将defaultProps
属性值赋到props
上
// 将 defaultProps 赋值到 props 上 if (type && type.defaultProps) { for (let propName in type.defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; } } }
- 组件默认的
-
整合成
js
对象
const REACT_ELEMENT_TYPE = Symbol.for('react.element');
let ReactCurrentOwner = {
current: null,
}
function createElement(type, props, children) {
// 处理 props
...
// 处理 children
...
// 处理 defaultProps
...
// 整合成 js 对象
const element = {
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: ref,
props: props,
_owner: ReactCurrentOwner.current, // 创建当前组件的对象,默认值为null
};
element._store = {};
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
value: true // 源码中是有校验函数,校验为合法的 React 对象后,value 才会变成 true 的,此处省略,直接为 true
});
Object.defineProperty(element, '_self', {
configurable: false,
enumerable: false,
writable: false,
value: self
}); // Two elements created in two different places should be considered
// equal for testing purposes and therefore we hide it from enumeration.
Object.defineProperty(element, '_source', {
configurable: false,
enumerable: false,
writable: false,
value: source
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
return element;
}
- 最后呈现的对象