https://github.com/facebook/react/blob/master/packages/react/src/ReactElement.js
// ** ReactElement 是 createElement的核心方法。作用是很简单,就是返回一个信息的承载容器,表明渲染节点的信息。
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// $$typeof 用来标识我们的Element的什么类型的。比如我们在写jsx代码的时候,所有的节点都是通过createElement创建的,那么它的$$typeof就永远是REACT_ELEMENT_TYPE,也就是说大部分情况下 这个值都是固定的。(用于确定是否属于ReactElement)
// 源码:const REACT_ELEMENT_TYPE = function() {}; // fake(虚假) Symbol
$$typeof: REACT_ELEMENT_TYPE,
type: type, // 记录节点类型,是原生组件还是class function Component or other
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner,
};
return element;
};
// ** createElement 源码
// 主要是对 props属性 的扩展;最终返回 ReactElement 的结果。
export function createElement(type, config, children) {
let propName;
const props = {};
// 下面这四个值,是根据 config的内容 进行获取的,若没有对应的值,则以null返回。
let key = null;
let ref = null;
let self = null;
let source = null;
// 注意 这里对 ref, key 是单独处理,赋予一个全新的变量。
if (config != null) {
if (hasValidRef(config)) { // 判断 ref 是否有效
ref = config.ref;
}
if (hasValidKey(config)) { // 判断 key 是否有效
key = '' + config.key;
}
// config中其余的 属性 则添加到新props对象中
for (propName in config) {
props[propName] = config[propName] // config去除key/ref 其他属性的放到props对象中
}
}
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
const childArray = Array(childrenLength); // 根据长度,创建含有对应个数的空数组。
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
};
{
//冻结array 返回原来的childArray且不能被修改 防止有人修改库的核心对象 冻结对象大大提高性能
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray; //父组件内部通过this.props.children获取子组件的值
props.children = childArray;
}
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}