createElement
createElement
允许你创建一个 React 元素。它可以作为编写 JSX 的替代方案。
const element = createElement(type, props, ...children)
参考
createElement(type, props, ...children)
调用 createElement
来创建一个 React 元素,它有 type
、props
和 children
三个参数。
import { createElement } from 'react';
function Greeting({ name }) {
return createElement(
'h1',
{ className: 'greeting' },
'你好'
);
}
参数
-
type
:type
参数必须是一个有效的 React 组件类型。例如,它可以是一个标签名字符串(如'div'
或'span'
),或一个 React 组件(一个函数式组件、一个类式组件,或者是一个特殊的组件,比如Fragment
)。 -
props
:props
参数必须是一个对象或null
。如果你传入null
,它会被当作一个空对象。React 会创建一个拥有与你传入的props
相匹配的元素。注意,props
对象中的ref
和key
是特殊的,它们 不会 作为element.props.ref
和element.props.key
出现在返回的element
上。它们会作为element.ref
和element.key
出现。 -
可选
...children
:零个或多个子节点。它们可以是任何 React 节点,包括 React 元素、字符串、数字、portal、空节点(null
、undefined
、true
和false
),以及 React 节点数组。
返回值
createElement
返回一个 React 元素对象,它有这些属性:
type
:你传入的type
。props
:你传入的props
,除了ref
和key
。如果type
是一个带有过时的type.defaultProps
的组件,那么任何缺失或未定义的props
都会从type.defaultProps
中获取值。ref
:你传入的ref
。如果缺失则为null
。key
:你传入的key
,会被强制转换为字符串。如果缺失则为null
。
通常你会从你的组件中返回这个元素,或者把它作为另一个元素的子元素。虽然你可以读取元素的属性,但最好在创建后将每个元素都视为不透明的,并且只渲染它。
注意事项
-
你必须 把 React 元素和它们的 props 视为 不可变的,并且在创建后永远不要改变它们的内容。在开发环境中,React 会浅层 冻结 返回的元素及其
props
属性,以强制执行此操作。 -
当你使用 JSX 时,你必须以大写字母开头来渲染你自己的自定义组件。换句话说,
<Something />
等价于createElement(Something)
,但<something />
(小写)等价于createElement('something')
(注意它是一个字符串,所以它会被当作内置的 HTML 标签)。 -
你应该只 在所有子元素都是静态可知的情况下,才将它们作为多个参数传递给
createElement
,比如createElement('h1', {}, child1, child2, child3)
。如果你的子元素是动态的,把整个数组作为第三个参数传递:createElement('ul', {}, listItems)
。这样可以确保 React 会 警告你缺少key
。对于静态列表这不是必须的,因为它们永远不会重新排序。
用法
不使用 JSX 创建元素
如果你不喜欢 JSX 或者不能在你的项目中使用它,你可以使用 createElement
作为替代方案。
要想不使用 JSX 创建一个元素,你可以调用 createElement
并传入 type、props 和 children:
import { createElement } from 'react';
function Greeting({ name }) {
return createElement(
'h1',
{ className: 'greeting' },
'你好',
createElement('i', null, name),
'。欢迎!'
);
}
children 是可选的,你可以传入任意数量(上面的例子有三个子元素)。这段代码会显示一个带有问候语的 <h1>
标题。为了对比,下面是用 JSX 重写的相同示例:
function Greeting({ name }) {
return (
<h1 className="greeting">
你好<i>{name}</i>,欢迎!
</h1>
);
}
要想渲染你自己的 React 组件,传入一个函数(比如 Greeting
)作为 type ,而不是一个字符串(比如 'h1'
):
export default function App() {
return createElement(Greeting, { name: '泰勒' });
}
如果使用 JSX,它看起来像这样:
export default function App() {
return <Greeting name="泰勒" />;
}
这里是一个完整的使用 createElement
的示例:
import { createElement } from 'react'; function Greeting({ name }) { return createElement( 'h1', { className: 'greeting' }, '你好', createElement('i', null, name), ',欢迎!' ); } export default function App() { return createElement( Greeting, { name: '泰勒' } ); }
这里是相同的示例,使用 JSX 编写:
function Greeting({ name }) { return ( <h1 className="greeting"> 你好<i>{name}</i>,欢迎! </h1> ); } export default function App() { return <Greeting name="泰勒" />; }
两种编码风格都可以,所以你可以在你的项目中使用你喜欢的那种。相比于 createElement
,使用 JSX 的主要好处是很容易看出哪个闭合标签对应哪个开放标签。
深入探讨
元素是用户界面的轻量级描述。比如,<Greeting name="泰勒" />
和 createElement(Greeting, { name: '泰勒' })
都会产生一个像这样的对象:
// 极度简化后
{
type: Greeting,
props: {
name: '泰勒'
},
key: null,
ref: null,
}
注意,创建这个对象并不会渲染 Greeting
组件或者创建任何 DOM 元素。
React 元素更像是一种描述——指示 React 之后渲染 Greeting
组件的指令。你从你的 App
组件中返回这个对象,就是告诉了 React 接下来该做什么。
创建元素非常高效,因此你不需要试图优化或者避免它。