前言
继续上一篇,还有4个API:
createElement,
cloneElement
createFactory
isValidElement
createElement
<div className="class" props="props" ref="ref" key="key">
<p>1</p>
<p>2</p>
</div>,
上面这段jsx代码通过babel转换后如下
React.createElement("div", {
className: "class",
props: "props",
ref: "ref",
key: "key"
}, React.createElement("p", null, "1"), React.createElement("p", null, "2"));
- 可以看到转换后会调用createElement函数
- 第一个参数是个domElement 字符串
- 第二个参数是个把标签上的属性转换成了一个对象
- 后面的参数也是createElement函数,分别是两个包裹在div中的p标签的创建,也就是children
// 不加入到props对象中的属性
const RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true
};
export function createElement(type, config, ...children) {
let propName;
const props = {};
let key = null;
let ref = null;
if (config !== null) {
key = config.key || null;
ref = config.ref || null;
}
if (config != null) {
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
// default props, 比如class App上挂了 App.defaultProps = {} 时的处理
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (!props[propName]) {
props[propName] = defaultProps[propName];
}
}
}
// react-dom 首次渲染 没有children参数
props.children =
children.length === 0
? null
: children.length === 1
? children[0]
: children;
return ReactElement(type, key, ref, props);
}
- 拿到config中的key和ref分别赋值给声明好的key和ref
- 遍历config中的属性,根据RESERVED_PROPS对象过滤不需要的属性,将剩下的属性全部保存到props这个对象中
- 将default中的属性拷贝到props中
- 保存children到props中
- 调用ReactElement
const ReactElement = (type, key, ref, props) => {
const element = {
$$typeof: REACT_ELEMENT_TYPE,
type,
ref,
key,
props: props
};
return element;
};
- 返回一个element对象
- `$$`typeof: 一个symbol标识,标识是什么类型的element,和前面的一些API里的稍有不通,前面一些API中的$$typeof是保存在type当中
- type:createElement的第二个参数
- ref:在createElement中提取的ref
- key:在createElement中提取的key
- props:在createElement中处理后的props
cloneElement
export function cloneElement(element, config, ...children) {
let propName;
const props = Object.assign({}, element.props);
let key = element.key;
let ref = element.ref;
if (config != null) {
if (config.ref !== undefined) {
ref = config.ref;
}
if (config.key !== undefined) {
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];
}
}
}
props.children =
children.length === 0
? null
: children.length === 1
? children[0]
: children;
return ReactElement(element.type, key, ref, props);
}
}
cloneElement的实现和createElement几乎一样,最后return的还是一个ReactElement对象,只不过第一个参数不同,第一个参数接收的是一个ReactElement,也就是createElement返回的那个对象
createFactory
export function createFactory(type) {
const factory = createElement.bind(null, type);
factory.type = type;
return factory;
}
- 返回一个createElement(type) 函数
这个API好像已经没用了,也用不到
isValidElement
/**
* 验证是否是react对象,主要是通过对象上的$$typeof属性
* @param {*} object
*/
export function isValidElement(object) {
return (
typeof object === "object" &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
}
- 一个验证是否是react对象的函数,主要是通过对象上的$$typeof属性
react这个包基本写完了
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。