Build your own React_1 createElement函数
Posted 一只前端小马甲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Build your own React_1 createElement函数相关的知识,希望对你有一定的参考价值。
前端工程师的要求越来越高,仅懂得“三大马车”和调用框架API,已经远不能满足岗位的能力要求。因此增强自身的底层能力,了解框架的内部原理非常重要。本系列文章,翻译自Rodrigo Pombo的《Build your own React》一文,同时每篇文章最后,都会加入自己的理解,一方面记录自己初探React框架原理的过程,另一方面也是想与各位大牛多多交流,以出真知。
我们打算从零开始重写一个React框架,在遵循源码架构的基础上,省略了一些优化和非核心功能代码。
假设你阅读过我之前的文章《build your own React》,那篇文章是基于React 16.8版本,当时还不能使用hooks来替代class。
你可以在Didact仓库找到那篇文章和对应的代码。这里还有个相同主题的视频,跟文章的内容有些区别的,但是可以参考观看。
从零开始重写React框架,我们需要遵循以下步骤:
步骤一:createElement函数
让我们使用另一个React程序示例。这次我们将用我们自己写的React框架来代替React代码。
const element = (
<div id="foo">
<a>bar</a>
<b />
</div>
)
const container = document.getElementById("root")
ReactDOM.render(element, container)
首先我们要编写自己的createElement函数,将JSX转化为JS代码,就能看到createElement函数的调用。
const element = React.createElement(
"div",
id: "foo" ,
React.createElement("a", null, "bar"),
React.createElement("b")
)
// const container = document.getElementById("root")
// ReactDOM.render(element, container)
在上一步骤中,我们知道React创造的元素实际上是拥有type和props属性的JS对象,createElement函数的作用就是返回这个对象。
我们对props属性使用扩展运算符,对children属性使用rest参数语法,这种方式得到的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源码里不会为基本数据类型包装一层,当元素没有children属性时,也不会有空数组。我们这么做是为了简化代码,我们重写的框架更看重简洁的代码而不是高效的性能。
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_ELEMETN",
props:
nodeValue: text,
children: [],
现在我们还在使用React的createElement函数,为了替换掉它,我们需要给我们的框架取个名字,类似React的同时,具有教学的(didactic)意义。
const element = React.createElement(
// "div",
// id: "foo" ,
React.createElement("a", null, "bar")
React.createElement("b")
)
不妨叫做Didact。
const Didact =
createElement,
const element = Didact.createElement(
// "div",
// id: "foo" ,
Didact.createElement("a", null, "bar"),
Didact.createElement("b")
)
但是我们又同时想使用JSX语法,如何告诉Babel使用Didact的createElement替代React的createElement函数呢?
只需要添加一个注释,告诉Babel在转化某处JSX时使用我们自己定义的函数。
/** @jsx Didact.createElement */
const element = (
<div id="foo">
<a>bar</a>
<b />
</div>
)
总结
步骤零中,作者解释了React元素的本质是JS对象,以及该JS对象是如何与实际的DOM节点关联起来的。
步骤一则展示了如何将React元素转化JS对象——通过createElement函数。React元素的标签名、props属性以及children属性被作为参数传入名为createElement的函数。前两个参数没有特别之处,children参数被转化为数组,数组元素值可能为基本数据类型或者对象,为了便于后面生成DOM节点的逻辑统一,作者将基本数据类型也“包装”成了对象。createElement函数最终返回一个JS对象,该对象保留了最初React元素中的信息。
上一篇传送门:Build your own React_0 总述
下一篇传送门:Build your own React_2 render函数
以上是关于Build your own React_1 createElement函数的主要内容,如果未能解决你的问题,请参考以下文章
Build your own React_4 理解React纤维