文件目录
packages/react/src/ReactElement
ReactElement
指定当前元素是 ReactElement, 但该元素是由 createElement 创建的, 来看一下ReactElement 源码
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
$$typeof: REACT_ELEMENT_TYPE, // 指Element元素
// 下面几个都是我们 元素的属性,
// eg. <div key="1" ref="string" value="123"></div>
type: type,
key: key,
ref: ref,
props: props,
// 记录负责创建此元素的组件。
_owner: owner, // 其实是一个FiberNode
};
return element;
};
createElement
根据type 创建一个ReactElement。同时处理ref, key, props, 还有children, 另外对defaultProps 赋值。
我们看一下babel 的转化吧!
<div key="1" ref="string" value="123">
<p>children1</p>
<p>children2</p>
</div>
会转换成
React.createElement(
"div",
{
ref: "string",
value: "123",
key: "1"
},
React.createElement(
"p",
null,
"children1",
)
React.createElement(
"p",
null,
"children12",
)
)
源码:
export function createElement(type, config, children) {
// type => div
// config => {ref: "string",value: "123",key: "1"}
// children => <p>children1</p>, <p>children2</p>
let propName;
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
// 验证config, 把key 和 ref 从config 单独抽离出来放到props 中
if (config != null) {
// 验证 ref 和 key
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
// self 正确获取this, 检测this与 ReactElement.owner是否相等,不相等就发出警告
// source 一个注释对象(由编译器或其他方式添加),指示文件名,行号和/或其他信息。
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// 遍历配置,把除了key, ref, _self, _source这些以外的数据放到props
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
// 处理children, arguments 后面的参数都是children
// 如果children 数大于1个,那么放入到数组中
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];
}
props.children = childArray;
}
// 判断是否有给组件设置 defaultProps,有的话判断是否有给 props 赋值,
// 只有当值为 undefined 时,才会设置默认值
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,
);
}
cloneElement
cloneElement 克隆元素, 大致跟createElement 的处理方式一样 。