什么是React.createElement?
React.createElement 是React提供的一个高阶函数,用于根据传入的参数动态地创建React元素。这个函数接收三个及以上的参数:元素类型(type)、属性(props)、以及子元素(children)。
React.createElement的工作原理
当你调用React.createElement时,它实际上会创建一个轻量级的对象,这个对象描述了你想在UI中渲染的React元素。这个对象包含了type、props、key(如果提供了的话)、ref(如果提供了的话)等关键信息。React后续会使用这些信息来构建和更新DOM。
const element = React.createElement(
'div',
{ id: 'myDiv', className: 'myClass' },
['Hello, React!', React.createElement('span', null, 'This is a span.')]
);
// element 对象大致结构
{
$$typeof: Symbol.for('react.element'),
type: 'div',
props: {
id: 'myDiv',
className: 'myClass',
children: ['Hello, React!', {/* span 元素的描述对象 */}]
},
key: null,
ref: null,
_owner: null,
_store: {}
}
源码
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) {
// 将 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 = {
// 标记这是个 React Element
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: ref,
props: props,
_owner: owner,
};
return element;
};
我们可以看到,这段代码将输入的三个参数打包成ReactElement返回,而ReactElement这个函数的返回值是一个React元素对象。也就是说,JSX的执行结果是一个ReactElement对象。
JSX与React.createElement的关系
实际上,在React中,我们通常使用JSX语法来定义React Element。然而,在浏览器实际运行之前,即在构建过程中,JSX会被Babel等编译器转换为React.createElement函数调用,这些调用会生成React Element对象。
比如我定义了这样一段jsx代码
<div key='1' classname='1'>
<span>11</span>
</div>
经过babel编译以后的结果
可以看到这个jsx的执行结果转换成了React.createElement函数调用
同样的,我们在React中打印出一个React Element对象
const jsx = <div key='1' classname='1'>
<span>11</span>
</div>
console.log(jsx);
实现React.createElement方法
function createElement(type, config, children) {
const props = {}
// 处理 config 对象
if (config) {
for (let propName in config) {
if (propName !== 'key' && propName !== 'ref') {
props[propName] = config[propName]
}
}
}
// 处理 children
if (children?.length) {
props.children = children.length > 1 ? children : children[0]
}
// 添加 key 和 ref 到 props中
if (config?.key) {
props.key = config.key
}
if (config?.ref) {
props.ref = config.ref
}
// 返回一个对象,描述了这个React元素
return {
$$$typeof: Symbol.for('react.element'), // 一个用于标记这是React元素的Symbol
type,
props,
key: props?.key || null,
ref: props?.ref || null
}
}
控制台测试
const children = [createElement('span', null, '11'), createElement('span', null, '22')]
const element = createElement('div', { key: '1', classname: '1' }, children)
console.log(element);