Build your own React_2 render函数

Posted 一只前端小马甲

tags:

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

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

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

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

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

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

步骤二:render 函数

接下来,我们来实现一个自己的ReactDOM.render函数。目前只考虑向DOM中添加节点的情况,以后再考虑更新和删除。

function render(element, container)
	// TODO create dom nodes


const Didact = 
	// createElement,
	render,


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

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

我们根据传入的标签名称生成一个DOM节点,之后将节点添加至容器中。

function render(element, container)
	const dom = document.createElement(element.type)

	container.appendChild(dom)

对于子元素递归采用相同的处理方式。

function render(element, container)
	// const dom = document.createElement(element.type)
	
	element.props.children.forEach(child=>
		render(child, dom)
	)

	// container.appendChild(dom)

对于文字类型元素的处理方式是:如果元素type属性为TEXT_ELEMENT,我们创建一个文字节点,而不是普通节点。

// function render(element, container)
	const dom = element.type ==="TEXT_ELEMENT"
		? document.createTextNode("")
		: document.createElement(element.type)

	// element.props.children.forEach(child=>
	//	render(child, dom)
	// )

	// container.appendChild(dom)
//

最后一件事情就是将React元素的props属性赋给生成的dom节点。

// function render(element, container)
	// const dom = element.type === "TEXT_ELEMENT"
	//	? document.createTextNode("")
	//	: document.createElement(element.type)

	const isProperty = key => key !== "children"
	Object.keys(element.props)
		.filter(isProperty)
		.forEach(name=> 
		dom[name] = element.props[name]
	)

	// element.props.children.forEach(child=>
// 

这就是render函数的所有内容,我们现在拥有了将JSX渲染为DOM的库。

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: []
		
	


function render(element, container)
	const dom = 
	element.type === "TEXT_ELEMENT"
	? document.createTextNode("")
	: document.createElement(element.type)

	const isProperty = key => key !== "children"
	Object.keys(element.props)
	.filter(isProperty)
	.forEach(name=>
		dom[name] = element.props[name]
	)

	element.props.children.forEach(child=>
		render(child, dom)
	)

	container.appendChild(dom)


const Didact = 
	createElement,
	render


/** @jsx Didact.createElement */
const element = (
	<div id="foo">
		<a>Bar</a>
		<b />
	</div>
)
const container = document.getElementById("root")
Didact.render(element, container)

总结

步骤一中,作者详解介绍了通过createElement函数将React元素转化JS对象,该对象是React元素变为实际DOM节点的中间形态。

步骤二则展示了,如何将这个中间形态转化为DOM节点——通过render函数。步骤一得到的JS对象、根DOM节点被作为参数传出名为render的函数。render函数首先将JS递归转化为DOM树,每个节点可能是文字类型也可能是普通DOM节点,最后将生成的DOM树添加至根DOM节点上。至此,我们已经能清楚的知道一个React元素是如何被转化为实际的DOM节点。

上一篇传送门:Build your own React_1 createElement函数
下一篇传送门:Build your own React_3 并发模式

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

Build your own React_4 理解React纤维

Build your own React_4 理解React纤维

Build your own React_0 总述

Build your own React_0 总述

Build your own React_8 Hooks

Build your own React_7 函数组件