今天想了比较久的时间,准备开启这一系列的文章,旨在对 React
系列的源码进行深度解析,其中包含但不限于 react、react-dom、react-router...
等一系列优秀的 React
系列框架,最后再一一实现这些框架的简易版本。
本篇文章将会是对 react 和 react-dom
渲染过程源码的深度解析,我们将从官方 API 以及一些简易 Demo 来进入 react
的内部世界,探讨其中奥妙。
本文解析的
react
版本为v16.13.0
,是我 fork 的官方仓库,源码地址。
结构剖析
我们先从最基础的结构开始解析,从上面这张图来看看。我们创建了一个 App
类,继承于 React.Component
类,在 render
生命周期函数中返回了一个 jsx
格式的 html
标签集合。我们打开控制台,查看创建的实例(如下图):
我们逐一分析其中比较关键的属性:
字段 | 解释 |
---|---|
props |
把 Component 组件比作函数,props 就是函数的入参 |
context |
context 就是在组件树之间共享的信息 |
refs |
访问原生 DOM 元素的集合 |
updater |
负责 Component 组件状态的更新 |
_reactInternalFiber |
App 实例对应的 FiberNode |
一个 Component
实例的大致结构我们就解析完了,我们现在需要由内到外的继续解析 Component
内部结构以及实现。
我们现在来看看 render
方法内部, 第 7 行
的内容属于 jsx
语法,是一种 html
语法格式类似的高级模板语法。这一段我们需要借鉴一下官方的一张图来进行解释:
从上图可以得知,jsx
语法都会被编译成 React.createElement
函数,标签属性以及标签内容都会编译成对应的入参,由此可知我们所写的 第 7 行
代码在编译后将会变成如下代码:
React.createElement("section", {
}, "Hello World");
而 React.createElement
所创建的对象就是 虚拟 DOM 树
,那么内部创建的工作流程是什么样的?带着这个问题,我们进入下一个章节。
React.createElement
我们刚才得知 jsx
语法将会被编译成 React.createElement
函数调用,而这个函数属于 React
对象上的一个方法,现在我们就可以开始进入到源码解析,查看内部实现。
上图就是 React.createElement
,我们先看最后返回的结果是 ReactElement
函数的执行结果,该函数最后返回的是一个 React Element
对象(后面会提到)。
所以 React.createElement
其实是一个工厂函数,用于创建 React Element
对象,我们再来看看这个工厂函数主要做了哪些工作。
11-29 行
:收集了config
中的一些字段,并且将其他非内置字段添加到props
对象中;31-40 行
:将入参中的children
参数挂载到props
的children
字段中;(本示例中"Hello World"
就是一个 “children
”)42-49 行
:收集组件(type
可能是字符串也有可能是Component
实例,例如<section /&