文件位置:packages/react/src/ReactElement.js
react的jsx语法最终会通过React.createElement方法转为虚拟dom,如下图所示
相关内容可以在react官网了解
https://reactjs.org/
* createElement()负责生成虚拟
* @param {type接受的是标签名称*} type
* @param {config接受的是包含的props,style,class等*} config
* @param {children 子节点的VNode对象 || 父元素的文本内容*} children
* @returns
*/
export function createElement(type, config, children) {
let propName;
// Reserved names are extracted
const props = {};
// 对于关键字处理
let key = null;
let ref = null;
let self = null;
let source = null;
// 判断config是否有值
if (config != null) {
if (hasValidRef(config)) {
ref = config.ref;
if (__DEV__) {
warnIfStringRefCannotBeAutoConverted(config);
}
}
if (hasValidKey(config)) {
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
// 对于children的处理,形参
const childrenLength = arguments.length - 2;
// length为1的情况,直接赋值
if (childrenLength === 1) {
props.children = children;
// 大于1,进行循环赋值
} else if (childrenLength > 1) {
// 新建数组长度为childrenLength的数组
const childArray = Array(childrenLength);
// 循环并赋值
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
// 最终把得到的childArray赋值给props点children
props.children = childArray;
}
// 是否存在默认的defaultProps
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
if (__DEV__) {
if (key || ref) {
const displayName =
typeof type === 'function'
? type.displayName || type.name || 'Unknown'
: type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
}
// 调用ReactElement方法,把处理的参数传递进去
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
* Factory method to create a new React element. This no longer adheres to
* the class pattern, so do not use new to call it. Also, instanceof check
* will not work. Instead test $$typeof field against Symbol.for('react.element') to check
* if something is a React Element.
*
* 工厂方法来创建新的React元素。这不再符合类模式,所以不要使用new来调用它。还有,检查实例
不起作用。而是对$$typeof字段进行测试符号.for('反应元素)进行检查
* @param {type为标签名称*} type
* @param {props自定义的属性、方法,注意:props.children=childArray*} props
* @param {key为null*} key
* @param {string|object} ref
* @param {*} owner
* @param {null*} self
* @param {null*} source
* @internal
*/
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// 这个标签允许我们唯一地将其标识为React元素
$$typeof: REACT_ELEMENT_TYPE,
// 属于元素的内置属性
type: type,
key: key,
ref: ref,
props: props,
// 记录负责创建此元素的组件。
_owner: owner,
};
if (__DEV__) {
element._store = {};
/**
* 为了便于测试验证标志不可枚举(如果可能,应该包括我们运行测试的每个环境),可以忽略
*/
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
value: false,
});
// self和source是仅适用于开发人员的属性
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;
};