createElement
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;
// 如果元素有属性
if (config != null) {
// 验证是否有 Ref prop,如果有则取出
if (hasValidRef(config)) {
ref = config.ref;
}
// 验证是否有 Key prop,如果有则取出,同时字符串化
if (hasValidKey(config)) {
key = '' + config.key;
}
// 用于测试、debug、准确抛出错误用的信息
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// 遍历 props,如果存在,并且并不与内部 props 冲突则合并到变量 props 中
// 简而言之,提取有用且有效的 props
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
// 第三个参数开始,后面的参数都可以是 children,所以后面的参数有多少决定了 children 有多少
const childrenLength = arguments.length - 2;
// 如果只有一个,则直接赋值
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
// 遍历入参,传到一个数组中,赋值到 children 中
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
props.children = childArray;
}
// 合并默认 props
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,
);
}
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
// 独一无二的表示,用于确认当前的元素是 react 的元素
$$typeof: 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.
// ReactCurrentOwner是一个对象,只有current一个属性,用于存储当前正在构建的Component所属的Component。
// ReactCurrentOwner.current主要在 react-dom 的ReactCompositeComponent中被赋值。
_owner: owner,
};
return element;
};
createFactory
// 用于生成快速生成某个组件的工厂函数的函数(真绕啊,汗
export function createFactory(type) {
const factory = createElement.bind(null, type);
// Expose the type on the factory and the prototype so that it can be
// easily accessed on elements. E.g. `<Foo />.type === Foo`.
// This should not be named `constructor` since this may not be the function
// that created the element, and it may not even be a constructor.
// Legacy hook: remove it
factory.type = type;
return factory;
}
cloneAndReplaceKey
// 克隆一个元素并重置其 key 值
export function cloneAndReplaceKey(oldElement, newKey) {
const newElement = ReactElement(
oldElement.type,
newKey,
oldElement.ref,
oldElement._self,
oldElement._source,
oldElement._owner,
oldElement.props,
);
return newElement;
}
cloneElement
export function cloneElement(element, config, children) {
// 类型校验
invariant(
!(element === null || element === undefined),
'React.cloneElement(...): The argument must be a React element, but you passed %s.',
element,
);
let propName;
// 浅拷贝被拷贝的元素的 props
const props = Object.assign({}, element.props);
// 获取被拷贝元素的 key,ref,_self,_source,_owner
// Reserved names are extracted
let key = element.key;
let ref = element.ref;
// Self is preserved since the owner is preserved.
const self = element._self;
// Source is preserved since cloneElement is unlikely to be targeted by a
// transpiler, and the original source is probably a better indicator of the
// true owner.
const source = element._source;
// Owner will be preserved, unless ref is overridden
let owner = element._owner;
// 获取新的元素配置,并覆盖被克隆元素传递下来的值
if (config != null) {
if (hasValidRef(config)) {
// Silently steal the ref from the parent.
ref = config.ref;
owner = ReactCurrentOwner.current;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
// Remaining properties override existing props
let defaultProps;
if (element.type && element.type.defaultProps) {
defaultProps = element.type.defaultProps;
}
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
if (config[propName] === undefined && defaultProps !== undefined) {
// Resolve default props
props[propName] = defaultProps[propName];
} else {
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;
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;
}
// 创建元素对象
return ReactElement(element.type, key, ref, self, source, owner, props);
}
isValidElement
// 通过元素的 $$typeof 判断该元素是不是 React 元素
export function isValidElement(object) {
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
}