Build your own React_0 总述

Posted 一只前端小马甲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Build your own React_0 总述相关的知识,希望对你有一定的参考价值。

前端工程师的要求越来越高,仅懂得“三大马车”和调用框架API,已经远不能满足岗位的能力要求。因此增强自身的底层能力,了解框架的内部原理非常重要。本系列文章,翻译自Rodrigo Pombo的《Build your own React》一文,同时每篇文章最后,都会加入自己的理解,一方面记录自己初探React框架原理的过程,另一方面也是想与各位大牛多多交流,以出真知。

我们打算从零开始重写一个React框架,在遵循源码架构的基础上,省略了一些优化和非核心功能代码。

假设你阅读过我之前的文章《build your own React》,那篇文章是基于React 16.8版本,当时还不能使用hooks来替代class。

你可以在Didact仓库找到那篇文章和对应的代码。这里还有个相同主题的视频,跟文章的内容有些区别的,但是可以参考观看。

从零开始重写React框架,我们需要遵循以下步骤:

步骤零:总述

首先来回顾一些基本概念。如果你非常熟悉React、JSX和DOM元素的工作机制,可以直接进入步骤一。

我们使用一个简单的React示例,只有三行代码。首行定义了一个React元素,次行获取了一个DOM节点,最后一行将React元素渲染在容器中。

我们要做的是把所有的React代码改写为原生JavaScript代码

const element = <h1 title="foo">Hello</h1>
const container = document.getElementById("root")
ReactDOM.render(element, container)

第一行我们定义了JSX语法的一个元素,但是并不是合法的javascript语法,因此我们需要做些修改。

const element = <h1 title="foo">Hello</h1>
// const container = document.getElementById("root")
// ReactDOM.render(element, container)

JSX通过类似于Babel这样的打包工具转化为JS代码。转化过程通常也很简单:将标签部分的代码代为调用createElement函数原标签名、props和children属性作为参数

const element = React.createElement(
	"h1",
	{ title: "foo" },
	"Hello"
)

// const container = document.getElementById("root")
// ReactDOM.render(element, container)

React.createElement的作用在于生成一个JS对象。我们不考虑校验问题,因此完全可以用对象代替函数调用的结果。

const element = {
	type: "h1",
	props: {
		title: "foo",
		children: "Hello",
	}
}

// container = document.getElementById("root")
// ReactDOM.render(element, container)

上面所说的React元素,实质上是个JS对象,具有type和props属性(可能有更多,但是我们目前只考虑这两个)。

type属性是个字符串,表示创建的DOM节点的类型,也是传给document.createElement函数的第一个参数tagName(标签名称)。

props属性是个对象,表示传递给节点的属性,它存储了所有从JSX传递来的键值对,同时有个特殊属性children。

children属性是可以是字符串,也可以是元素数组。这是React元素的数据结构为树的原因。

另外需要替换的React代码是ReacDOM.render。

ReactDOM.render(element, container)

render函数是React修改DOM的函数,现在让我们自己实现一次。

  • 首先根据元素type创建一个节点,这个例子是h1。
  • 然后将元素的props属性赋给DOM节点,这个例子中只有title。
  • *为了避免歧义,我们使用元素指代React元素,节点指代DOM节点
const element = {
	type: "h1",
	// props: {
		title: "foo",
		// children: "Hello",
	//},
}

const container = document.createElement(element.type)
node["title"] = element.props.title

// const text = document.createTextNode("")
// text["nodeValue"] = element.props.children

接着根据children属性创建子节点,这个例子中children属性值是字符串,因此只需要创建一个文字节点。

使用textNode而不是innerhtml保证了所有元素都能按照这种逻辑处理,我们处理nodeValue的方式跟处理之前h1标签的title属性一样,可以看作字符串拥有的props属性为:{ nodeValue: “Hello” }

const element = {
	//type: "h1",
	//props: {
		//title: "foo",
		children: "Hello"
	//}
}

//const container = document.getElementById("root")

//const node = document.createElement(element.type)
//node["title"] = element.props.title

const text = document.createTextNode("")
text["nodeValue"] = element.props.children

最后,我们将textNode添加至h1,h1添加至container,得到了JavaScript改造后的程序。

const element = {
	type: "h1",
	props: {
		title: "foo",
		children: "Hello"
	}
}

const container = document.getElementById("root")

const node = document.createElement(element.type)
node["title"] = element.props.title

const text = document.createTextNode("")
text["nodevalue"] = element.props.children

node.appendChild(text)
container.appendChild(node)

总结

步骤零使用一个小例子,展示了React元素的本质是JS对象,React根据JS对象中的信息去生成DOM树,而生成树的过程就是我们最熟悉的JS语法,例如:createElement、createTextNode、appendChild这些常见的api。

JSX语法JS语法(本质)
React生成元素React工作本质

了解这个工作过程是非常重要的,首先这是后面章节学习的基础,其次也能让我们慢慢体会到React的设计哲学。来,准备单脚踏入React的大门了:)

下一篇传送门: Build your own React_1 createElement函数

以上是关于Build your own React_0 总述的主要内容,如果未能解决你的问题,请参考以下文章

Build your own React_4 理解React纤维

Build your own React_4 理解React纤维

Build your own React_8 Hooks

Build your own React_7 函数组件

Build your own React_8 Hooks

Build your own React_7 函数组件