React系列(2) ReactElement
react/src/ReactElement.js
React.createElement做了什么
- 先判断config中内置props(key,ref,self,source)存在且有效,则赋值给新声明的变量
- 再将config中非内置的props 给新声明的props(key和ref不会跟其他config中的变量一起被处理,而是单独作为变量出现在ReactElement上。)
- 判断如果孩子节点为一个,则赋值给props.children。如果孩子节点有多个,则将其以数组的形式赋值给props.children
- 如果存在默认值,且存在默认值的属性在props数组中为undefined,则将该属性赋值为默认值。(为null不赋值为默认值)
- 返回一个ReactElement对象
export function createElement(type, config, children) {
let propName;
// Reserved names are extracted
const props = {};
let key = null;
let ref = null;
let self = null; // 用于dev
let source = null; // 用于dev
if (config != null) { // 处理config中的属性
if (hasValidRef(config)) {
// config里存在合理的ref就将其放入之前声明的ref变量
ref = config.ref;
}
if (hasValidKey(config)) {
// config里存在合理的key就将其放入之前声明的key变量
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
// config.__self存在就放入self 用于dev
source = config.__source === undefined ? null : config.__source;
// config.__source存在就放入source 用于dev
// Remaining properties are added to a new props object
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
// 如果config里有props并且RESERVED_PROPS里没有,就将其放到props对象里
/*
const RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true,
};
*/
props[propName] = config[propName];
}
}
}
// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
const childrenLength = arguments.length - 2;
// 除去type 和 config 剩下的是children
if (childrenLength === 1) {
// children的长度为1时props的children就是传入的最后一个参数children
props.children = children;
} else if (childrenLength > 1) {
// children的长度大于1时,说明有多个子节点,就生成一个数组childArray,将所有children放入childArray里
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
// props.children 赋值为 childArray
props.children = childArray;
}
// Resolve default props
// 如果是继承于React.Component的class Comp时,可以设置defaultProps默认值。
if (type && type.defaultProps) { // 如果组件存在并存在默认值
const defaultProps = type.defaultProps; // 定义defaultProps为默认值
for (propName in defaultProps) {
if (props[propName] === undefined) { // props[propName]为null时 不使用默认值
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,
);
}
ReactElement的内容
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
// $$typeof表示element的类型,通过creatElement创建的都是REACT_ELEMENT_TYPE
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner,
};
if (__DEV__) {
// The validation flag is currently mutative. We put it on
// an external backing store so that we can freeze the whole object.
// This can be replaced with a WeakMap once they are implemented in
// commonly used development environments.
element._store = {};
// To make comparing ReactElements easier for testing purposes, we make
// the validation flag non-enumerable (where possible, which should
// include every environment we run tests in), so the test framework
// ignores it.
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
value: false,
});
// self and source are DEV only properties.
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;
};
typeof表示element的类型,通过createElement创建的reactElement的$$typeof的值都为REACT_ELEMENT_TYPE
type是ReactElement的类型可能值为
- 原生DOM标签:HostComponent
- 继承于react.Component或react.PureComponent的组件:ClassComponent
- 函数组件:Functional Component
- React的内置组件 :
- Fragment: REACT_FRAGMENT_TYPE
- Profiler: REACT_PROFILER_TYPE
- StrictMode: REACT_STRICT_MODE_TYPE
- Suspense: REACT_SUSPENSE_TYPE
- unstable_SuspenseList: REACT_SUSPENSE_LIST_TYPE
- TODO:其他
由此便通过createElement创建了ReactElement