React-简单组件渲染(render)过程

By
写代码

没有需求就没有任务,没有任务就不想看代码。但是对于分配了代码讲解任务的人来说,终于还是有不得不看代码的“任务”。

C或者Java等“严谨语言圈”对阅读源码有一种谜样的执着,仿佛大神都是从阅读源码一步一步修炼过来的。但是对于“不严谨”的JavaScript语言圈来说,却明显缺少这样的执着。究其原因,各端兼容占了60%的时间,然后滚滚而来的需求和层出不穷的轮子,让JS码农甚至无暇顾及代码的可读性;JS天生的“不确定性”,也让接触的人摸不着头脑,而JS的进步也并不靠本身的规范和增强,而是全靠工具库、轮子和社区贡献。所以读代码的时候,下一个轮子已经碾压过去了。

但是读代码就没有用了吗?至少看一下代码设计的新思路,这门语言的“奇巧淫技”般的写法,或者做一些“魔改”,都是大有好处的。

下面正文开始。

不管是官方例子或各种教程介绍里,对于初次使用React组件,应该都会有个类似下面的例子:

上面代码使用了JSX语法,由JSX编写的代码是无法在浏览器中运行的,需要用Babel来将它编译成正常的JavaScript表达式。关于这部分如果有疑惑,可以参考 官方说明
最终编译结果大概是这样:

以调试方式查看代码

源代码是react-15-stable版本,这是一个比较老的版本,使用的是Stack引擎,新版本(react-16+)使用的是Fiber,但是整体结构已经比较完善。有时候,从比较初期的版本往后看,能对代码整体脉络和结构由更准确地把握。

代码查看,推荐使用调试工具。起初啥都没用,就直接挨个文件找function,然后对应几篇代码讲解文章,看的云里雾里。后来突然看到一篇文章以调试顺序讲解代码,打开WebStorm的调试,笑出了猪声。

WebStorm,配合chrome插件。这个组合可以很方便地在WebStorm里单步调试,比chrome自带的调试工具功能丰富,查看代码的运行情况也更方便。

关于如何使用WebStorm在chrome里调试JS,请看 这里

调试目标文件,可以自己写个简单的例子,调用编译之后的react.jsreact-dom.js文件(位于build目录)。或者直接打开example目录,几个基础的例子就够用了。

调用栈里用到的标签
– 函数调用
= 别名

初次简单渲染

这里叫初次简单渲染,是因为直接在根节点渲染只有一级的简单组件,只渲染一次,不包含状态更新和其他生命周期函数操作。

整体流程

react-render-overall

下面所有函数所在文件均位于react-dom/lib/

从编译后的代码可以看出,ReactDOM.render这个函数就是唯一入口了。

_renderSubtreeIntoContainer主要负责以下任务:

1.包装nextElement(仍然使用ReactElement.createElement

2.判断有无父级ReactElement元素,这里从根节点创建的,所以没有(从react的dom树中取:

如果有,需要更新父级元素。

3.判断是否有react标记,且不包含非根的react元素,决定是否重用标记shouldReuseMarkup

4.向虚拟DOM里渲染一个新的react根组件

下面仅列出batch调用栈,暂时忽略BatchingStrategy运行机制

5.最终的渲染会在transaction中执行(暂时忽略transaction的运行机制)

document.createElement等函数,把markup插入页面。

小记

1.步骤4中如何确定实例化的对象类型,比如Hello自定义标签,div等HTML标签,或者字符串?

instantiateReactComponent函数会根据type==TopLevelWrapper,确定instance的实例类型:

注意文件结尾

所以this.cunstruct使用的是ReactCompositeComponent的构建函数,即实例化了一个ReactCompositeComponent组件。

而根据不同的type类型,还会实例化为ReactDOMComponent(HTML标签)和ReactDOMTextComponent(文本节点)。

jsx-to-vdom

在React中,并没有名为“Virtual DOM”的文件或者类。而上面3中实例化的类型,差不多就是react中的虚拟DOM(Virtual DOM)了。因为这几个组件,包含了需要创建浏览器DOM需要的所有信息。

2.react节点包装过程

1)ReactDOM.render时生成的原始组件

react-render1

2)_renderSubtreeIntoContainer包装TopLevelWrapper

react-render2

3)instantiateReactComponent时实例化组件

react-render3

步骤3执行了ReactCompositeComponentconstruct构建函数

接下来…

ReactCompositeComponent.mountComponentsetState更新过程batchedUpdatesTransaction

参考网址:

  1. 深入理解React源码
  2. Under-the-hood-ReactJS
您已经发表过意见了!

Comments: 3

  1. 云里雾里没看懂……没用到不想学

    2018年12月05日
  2. 这算冷门和更高境界,就是别人看不懂,哈哈。

    2018年12月07日

发表评论

您的电子邮箱地址不会被公开。

*

:razz: