本篇主要基于源码谈谈jsx被编译之后,react在创建react element时做了什么
关于jsx的基础知识可以看看另一篇博客
由浅入深理解jsx
二、关于CreateElement
jsx被babel等编译工具转换之后,实质上是React.createElement方法。在react/packages/react/src/React.js文件中,我们可以发现这个方法有两个来源,在开发模式下,会使用携带校验功能的cloneElementWithValidation,否则使用ReactElement模块定义的createElement
import {
createElement,
} from './ReactElement';
import {
cloneElementWithValidation,
} from './ReactElementValidator';
const React = {
createElement: __DEV__ ? createElementWithValidation : createElement,
二、类型校验
1. 校验react元素类型
react内部采用Symbol对react元素类型进行区分,如果环境不支持ES6 Symbol,那么使用16进制数字去polyfill
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
// react元素类型
export const REACT_ELEMENT_TYPE = hasSymbol
? Symbol.for('react.element')
: 0xeac7;
export const REACT_PORTAL_TYPE = hasSymbol
? Symbol.for('react.portal')
: 0xeaca;
export const REACT_FRAGMENT_TYPE = hasSymbol
? Symbol.for('react.fragment')
: 0xeacb;
export const REACT_STRICT_MODE_TYPE = hasSymbol
? Symbol.for('react.strict_mode')
: 0xeacc;
export const REACT_PROFILER_TYPE = hasSymbol
? Symbol.for('react.profiler')
: 0xead2;
export const REACT_PROVIDER_TYPE = hasSymbol
? Symbol.for('react.provider')
: 0xeacd;
export const REACT_CONTEXT_TYPE = hasSymbol
? Symbol.for('react.context')
: 0xeace;
export const REACT_CONCURRENT_MODE_TYPE = hasSymbol
? Symbol.for('react.concurrent_mode')
: 0xeacf;
export const REACT_FORWARD_REF_TYPE = hasSymbol
? Symbol.for('react.forward_ref')
: 0xead0;
export const REACT_SUSPENSE_TYPE = hasSymbol
? Symbol.for('react.suspense')
: 0xead1;
export const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
export const REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
// 校验元素类型是否合理
export default function isValidElementType(type: mixed) {
return (
typeof type === 'string' ||
typeof type === 'function' ||
// Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
type === REACT_FRAGMENT_TYPE ||
type === REACT_CONCURRENT_MODE_TYPE ||
type === REACT_PROFILER_TYPE ||
type === REACT_STRICT_MODE_TYPE ||
type === REACT_SUSPENSE_TYPE ||
(typeof type === 'object' &&
type !== null &&
(type.$$typeof === REACT_LAZY_TYPE ||
type.$$typeof === REACT_MEMO_TYPE ||
type.$$typeof === REACT_PROVIDER_TYPE ||
type.$$typeof === REACT_CONTEXT_TYPE ||
type.$$typeof === REACT_FORWARD_REF_TYPE))
三、属性添加
1. children
如果root只有一个子节点,那么直接把它作为props.children
如果root没有子节点,那么props.children为undefined
如果子节点个数大于1,那么提取形参列表将子节点浅拷贝到childArray,将其作为props.children
在实际开发中,这种方式在处理单个子节点的组件情况下是较好的,相比之下它不必每次遍历形参列表,时间复杂度从O(n)降级到O(1)
因此,在使用props.children时需要注意的是,props.children可能的类型为undefined、ReactElement、Array。应对这种情况官方推出了React.children这个API,如React.children.map/forEach,它在底层对props.children类型做了兼容处理,是更为推荐的操作props.children的方式
export function createElement(type, config, 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;
2. 处理props与defaultProps
先为props添加属性,然后用defaultProps混入props,仅当props中对应属性为undefined时才会将其覆盖
defaultProps作用是在props未声明某属性时,为其提供默认值
export function createElement(type, config, children) {
// 处理props
for (propName in config) {
hasOwnProperty.call(config, propName) &&
// RESERVED_PROPS 是一些内建属性,比如key和ref,它们是react元素上的属性,不会被添加到props中
!RESERVED_PROPS.hasOwnProperty(propName)
props[propName] = config[propName];
// 处理defaultProps
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
四、生成ReactElement
createElement最终会调用ReactElement方法,该方法会将react元素的类型标记为REACT_ELEMENT_TYPE并返回一个object
export function createElement(type, config, children) {
return ReactElement(
type,
self, // 辅助属性,用于记录this
source, // 源信息,用于存储行数,文件名等等
ReactCurrentOwner.current, // Fiber对象
props,
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: ref,
props: props,
_owner: owner
return element;
最后我们得到一个结构如下所示的对象
文中代码关联的React版本: 16.8。