React.createElement的源码中做了如下几件事
- 处理config,把除了保留属性外的其他config赋值给props
- 把children处理后赋值给props.children
- 处理defaultProps
- 调用ReactElement返回一个jsx对象(virtual-dom)
推荐:babel编译jsx 站点查看jsx被编译后的结果
// ReactElement.js
export functin createElement(type, config, children) {
let propName;
const props = {}
let key = null;
let ref = null;
let self = null;
let source = null;
if (config != null) {
// 处理config,把除了保留属性外的其他config赋值给props
// ...
}
const childrenLength = arguments.length - 2;
// 把children处理后赋值给props.children
// ...
// 处理defaultProps
// ...
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
)
}
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
$$typeof: REACT_ELEMENT_TYPE, // 表示是ReactElement类型
type: type, // class 或function
key: key,
ref: ref,
props: props, // props
_owner: owner,
}
return element;
}
注:React.createElement方法,会把子节点,作为参数依次排开,比如:
function C() {
return <div></div>
}
class B {
render() {
return <div></div>
}
}
class A {
render() {
return <div name="a">aaa<B/></div>
}
}
上面的 aaa 和B组件就是并排展开的
$$typeof
typeof === REACT_ELEMENT_TYPE来判断的、
//ReactElement.js
export function isValidElement(object) {
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
}
type
- 如果这个组件时ClassComponent,则type是class本身
- 如果组件是FunctionComponent创建的,则type是这个function
- 普通节点,字符串
源码中用ClassComponent.prototype.isReactComponent来区分二者
注意:class和function创建组件一定要首字母大写,不然会被当作普通节点,type就是字符串
jsx对象和fiber
jsx对象上没有优先级、状态、effectTag等标记,这些标记在Fiber对象上,在mount时Fiber根据jsx对象来构建,在update时根据最新状态的jsx和current Fiber对比,形成新的workInProgress Fiber,最后workInProgress Fiber切换成current Fiber。