createElement

const element = (
<div id="foo">
<a>bar</a>
<b />
</div>
)
const element = React.createElement(
"div",
{ id: "foo" },
React.createElement("a", null, "bar"),
React.createElement("b")
)

正如我们在上一章看到的,一个元素是一个具有 type 和 props 的对象。我们的函数需要做的唯一事情就是创建这个对象。

我们对 props 使用扩展运算符,对 children 使用剩余参数语法,这样 children 将永远是一个数组。

function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children,
},
}
}
// createElement("div")
{
"type": "div",
"props": { "children": [] }
}
// createElement("div", null, a)
{
"type": "div",
"props": { "children": [a] }
}
// createElement("div", null, a, b)
{
"type": "div",
"props": { "children": [a, b] }
}

children 数组也可以包含原始值,如字符串或数字。因此,我们将把所有不是对象的东西包在自己的元素里,并为它们创建一个特殊的类型 -- TEXT_ELEMENT。

React 不会包裹原始值,也不会在没有孩子的时候创建空数组,但我们这样做是因为它可以简化我们的代码,对于我们的库来说,我们更喜欢简单的代码,而不是性能好的代码。

function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children: children.map(child =>
typeof child === "object"
? child
: createTextElement(child)
),
},
}
}
function createTextElement(text) {
return {
type: "TEXT_ELEMENT",
props: {
nodeValue: text,
children: [],
},
}
}

接下来,为我们的库取个名字代替 React,如 Didact

...
const Didact = {
createElement,
}
const element = Didact.createElement(
"div",
{ id: "foo" },
Didact.createElement("a", null, "bar"),
Didact.createElement("b")
)

最后,添加注释,使 babel 转译时使用 Didact.createElement 而不是 React.createElement

/** @jsx Didact.createElement */
const element = (
<div id="foo">
<a>bar</a>
<b />
</div>
)