ReactElement
/**
* 生成react元素的工厂方法,不再采用类模式,因此不能使用new调用
* 不支持instanceof检测类型
* 而只能通过$$typeof === Symbol.for('react.element')判断是否是react元素
*/
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// react元素标识,REACT_ELEMENT_TYPE = hasSymbol? Symbol.for('react.element'): 0xeac7;
$$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.
_owner: owner,
};
return element;
};
jsx方法
/**
* @param {*} type
* @param {object} props
* @param {string} key
*/
export function jsx(type, config, maybeKey) {
// 属性名,避免重复声明
let propName;
// Reserved names are extracted
const props = {};
let key = null;
let ref = null;
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
// 将config中包含的属性(除key,ref,__self,__source)浅拷贝到props对象中
for (propName in config) {
if (
/* const RESERVED_PROPS = {
* key: true,
* ref: true,
* __self: true,
* __source: true,
*/
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
// maybeKey赋值给key
if (maybeKey !== undefined) {
key = '' + maybeKey;
}
// 设置默认属性
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,
undefined,
undefined,
ReactCurrentOwner.current,
props,
);
}
createElement
实现代码多处和jsx相同
/**
* Create and return a new ReactElement of the given type.
* See https://reactjs.org/docs/react-api.html#createelement
*/
export function createElement(type, config, children) {
let propName;
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
if (config != null) {
if (hasValidRef(config)) {
ref = config.ref;
}
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;
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];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
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,
);
}
createFactory
生成type类型的react元素。 官网上说这是遗留下来的方法,目前鼓励使用jsx方法或者直接使用createElement方法。
export function createFactory(type) {
const factory = createElement.bind(null, type);
// 直接暴露类型,使得`<Foo />.type === Foo`
factory.type = type;
return factory;
}
cloneAndReplaceKey
使用新的key克隆react对象,搜索后发现在源码ReactChildren中有使用。
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) {
// element不能为null或undefined,否则报错
invariant(
!(element === null || element === undefined),
'React.cloneElement(...): The argument must be a React element, but you passed %s.',
element,
);
let propName;
// 复制要复制react元素的属性值
const props = Object.assign({}, element.props);
let key = element.key;
let ref = element.ref;
const self = element._self;
const source = element._source;
let owner = element._owner;
if (config != null) {
if (hasValidRef(config)) {
ref = config.ref;
owner = ReactCurrentOwner.current;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
// 默认属性
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
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
判断是否是react元素
export function isValidElement(object) {
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
}