chenxd1996

2018-08-06 11:49

React源码分析之初始渲染

本文作者:IMWeb chenxd1996 原文出处:IMWeb社区 未经同意,禁止转载

React 源码学习之初始渲染

前言: 前段时间笔者对React源码进行了学习,对于React一些原理有了更深的理解,但一些细节可能还不是很清楚,在这里与大家分享一下我对于React源码的一些理解。

本文基于React 15.6,现在React 16.4已经出来了,16版本与之前版本的代码差距还是比较大的,阅读难度也加大了,所以先从15版本入手会更好理解一些。

React源码学习中,我主要是了解了React中两个重要过程的源码。一是初始渲染,二是UI更新,这两部分应该就是React源码的核心了,网上也有很多博客对这两部门的源码进行分析,但推荐大家还是要自己去看源码,因为笔者在看源码之前看了很多篇博客,还是感觉似懂非懂,还是要身体力行啊,别偷懒~

源码解析要说清楚细节很难,篇幅上可能得花上七、八篇博客,所以我在这篇博客中只简单介绍React初始渲染和,略去很多代码,大家有兴趣再细致去阅读源码。

我们先来看下这个例子

image-20180806105049586

这个例子很简单,我们关注到

ReactDOM.render(<App />, document.getElementById('root'));

`<App />经过babel转译过后,会创建出一个React Element:

image-20180806105440203

这个东东其实就是虚拟DOM了,这里看到虚拟DOM的优点了,因为它比真实的HTML Element少了好多属性,这样创建、销毁虚拟DOM就会比操作真实DOM快很多了。

接下来我们来看下ReactElement这几个属性分别是什么:

$$typeof:标识这个对象是React Element

type: 元素的类型,可能是string 或者 function 或者 class

key: 元素的唯一标识

ref: 元素的ref, 真实Dom的引用

props: 元素的props,例如children,style

_owner:创建这个元素的元素

简略一下,ReactElement就变成这样了:

image-20180806105940902

接下来,React源码会在这个App元素外面包一层TopLevelWrapper,然后创建出一个新的ReactElement

image-20180806110619787

这个TopLevelWrapper其实很简单,我们只要知道它原型上的render方法,会返回this.props.child,而这个this.props.child指的就是前面的App元素。

image-20180806110720570

可能大家会有疑问,做了这一层包装有什么用呢?React源码中的解释是这样的:

image-20180806110939144

简单来说,就是ReactDOM.render(<XX />)这里的XX可能是类似div,span这样的host组件,也可能是React Component,包一层之后,根组件就可以统一当成React Component来处理了。

下面是TopLevelWrapper元素和APP元素的关系图

image-20180806111159543

接下来,React源码会通过ReactElement(T)去创建内部实例,所谓内部实例,就是React源码中用来管理组件的内部组件实例。image-20180806111345468

实际返回ReactCompositeComponent实例。

image-20180806111353166

React源码中有三种内部组件:

  1. ReactDOMTextComponent用来管理text node对应的ReactElement。
  2. ReactDOMComponent用来管理html标签对应的ReactElement。
  3. ReactCompositeComponent用来管理自定义组件对应的ReactElement。

它们都有以下四个重要方法来管理组件:

  1. construct用来接收ReactElement进行初始化。
  2. mountComponent用来生成ReactElement对应的真实DOM节点。
  3. unmountComponent卸载DOM节点,解绑事件。
  4. receiveComponent用来接收虚拟DOM的下一个状态,然后进行更新

下面是ReactCompositeComponent、ReactElement(T)、ReactElement(A)三者的关系图:

image-20180806111854522

接下来通过ReactCompositeComponent,React开始它的初始渲染。

初始渲染分为两个过程

image-20180806113752693

  1. 创建真实DOM 结点
  2. 将DOM结点插入到DOM树中

创建真实DOM结点的过程称为挂载,以ReactReconciler.mountComponent作为入口进行递归挂载,不断调用内部实例的mountComponent方法,最后得到一棵DOM子树。

image-20180806114005367

通过挂载后,再将DOM子树插入到容器中,初次渲染完成,Hello World显示在屏幕上。

image-20180806114318411

0条评论

    您需要 注册 一个IMWeb账号或者 才能进行评论。