createElement 执行过程
React createElement 函数的执行流程和实现原理
问题
React 中 createElement 函数是如何执行的?JSX 是如何转换成虚拟 DOM 的?
解答
JSX 到 createElement
JSX 代码会被 Babel 编译成 createElement 调用:
// JSX 写法
const element = <div className="box">Hello</div>;
// 编译后
const element = React.createElement('div', { className: 'box' }, 'Hello');
createElement 函数签名
createElement(type, config, ...children)
type: 元素类型,可以是字符串(如 ‘div’)或组件config: 属性配置对象children: 子元素
执行过程
function createElement(type, config, ...children) {
// 1. 初始化 props 对象
const props = {};
// 2. 提取保留属性
let key = null;
let ref = null;
if (config != null) {
// 提取 key
if (config.key !== undefined) {
key = '' + config.key;
}
// 提取 ref
if (config.ref !== undefined) {
ref = config.ref;
}
// 3. 复制其他属性到 props
for (const propName in config) {
if (
Object.hasOwnProperty.call(config, propName) &&
propName !== 'key' &&
propName !== 'ref'
) {
props[propName] = config[propName];
}
}
}
// 4. 处理 children
if (children.length === 1) {
props.children = children[0];
} else if (children.length > 1) {
props.children = children;
}
// 5. 处理 defaultProps
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (const propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
// 6. 返回 ReactElement 对象
return {
$$typeof: Symbol.for('react.element'), // 标识这是 React 元素
type,
key,
ref,
props,
};
}
完整示例
// 嵌套 JSX
const app = (
<div id="app">
<h1>Title</h1>
<p>Content</p>
</div>
);
// 编译结果
const app = React.createElement(
'div',
{ id: 'app' },
React.createElement('h1', null, 'Title'),
React.createElement('p', null, 'Content')
);
// 最终生成的对象结构
{
$$typeof: Symbol(react.element),
type: 'div',
key: null,
ref: null,
props: {
id: 'app',
children: [
{ $$typeof: Symbol(react.element), type: 'h1', props: { children: 'Title' } },
{ $$typeof: Symbol(react.element), type: 'p', props: { children: 'Content' } }
]
}
}
关键点
key和ref是保留属性,不会出现在props中children会被放入props.children,单个子元素不是数组$$typeof用于标识 React 元素,防止 XSS 攻击(JSON 无法包含 Symbol)defaultProps只在属性值为undefined时生效- createElement 只创建描述对象,不涉及真实 DOM 操作
目录