接上文---html
完整流程图见:https://bogdan-lyashenko.gith...
继续咱们的React之旅,让咱们从ReactDOM.render的调用开始。git
ReactDOM.render是咱们分析的入口点。咱们的应用从这里开始渲染内容到DOM树中。为了方便调试,咱们建立了一个<ExampleApplication/>的简单组件。整个流程的第一个动做就是把JSX转换成React elements 。 React elements就是带一些架构的简单对象。 他们就是用来表示组件render方法的返回值,除此以外,没有其余的。对象中的一些字段,如props,key,ref对于你们应该已经很熟悉了。 type属性表示的是JSX定义的标记对象,在咱们的案例中,就是类 ExampleApplication, 固然,它也能够表示 Button标签的字符串格式等等。 同时,在React element的建立期间,React将会合并defaultProps和props(若是有声明的话),而且严重propTypes。
更多详情请查看源码 srcisomorphicclassicelementReactElement.jsgithub
在流程图中,你能够发现有个叫作ReactMount的模块。它包含了整个组件挂载的逻辑。
其实,ReactDOM中是没有任何逻辑的,它不过是一个用来调用ReactMount的接口,因此当调用ReactDOM.render方法时,技术上来讲,你真正调用的是ReactMount.render方法。那么整个挂载过程究竟是怎么样的呢?缓存
Mounting is the process of initializing a React component by creating its representative DOM elements and inserting them into a supplied container.(挂载是指初始化一个React组件的过程,包括生成组件对应的DOM元素并插入指定的容器中)
以上文字来自于React代码的注释,那么这些究竟是一个怎么样的过程呢?咱们先看下如下的一个转化:
React须要将你组件里的JSX描述转化为对应的HTML结构,并插入到DOM树中,这个过程,
React须要处理全部的属性,绑定的事件,内嵌的组件和全部逻辑。挂载,就是指把用高层次语言描述的组件(JSX)转化为低层次的html代码,而后插入到DOM树中。架构
为了让以上描述更具体下,考虑以下需求:app
目标:确保滚动事件被监听
在一个根组件的第一次渲染过程当中,React会初始化滚动监听事件,而且把滚动条相关数值缓存起来,这样,当应用代码能够在不触发重排(reflow)的前提下,访问到滚动条相关数据。因为不一样的游览器会有不一样的实现,一些DOM的数值是非固定的,每次当你在代码中获取它们时,它们都有可能会从新计算。显然,这一步骤会引发一些性能问题。好比,一些老的游览器,是不支持pageX和pageY属性的。为了解决这个问题,React会作一些优化,而这些优化过程当中,可能就会须要不少其它技巧。在其它问题中,React为了解决某个具体的问题,都会用到不少技巧,滚动条就是一个具体的列子。
回顾下最开始的流程图,这里有一个实例建立的过程。事实上,目前去建立一个<ExampleApplication>的实例还有点早,这里咱们真正实例化的是类TopLevelWrapper(React内部类)。咱们先跳过这个过程,看下一个流程。dom
在JSX的转化过程当中,这里有三个阶段。JSX转化成React elements后,React elements会被转化为如下内部React组件类型中的一:ReactCompositeComponent(开发自定义的组件),ReactDOMComponent(HTML DOM节点),ReactDOMTextComponent(文本节点)。咱们先忽略ReactDOMTextComponent,重点放在前两个。svg
什么是内部组件呢?你可能已经听过虚拟DOM。虚拟DOM是一种DOM的表示方式,在React的diff差别计算以及其它过程当中,使用虚拟DOM使得能够不直接DOM树,而这恰是React性能不错的缘由之一。其实,在React的源码中,并无什么文件或者类被称做虚拟DOM,由于虚拟DOM只是一种概念,一种用来描述如何处理真实DOM的手段。有些人可能会说虚拟DOM表示的就是React elements,可是我不这么认为。在我看来,虚拟DOM指的是这三个类:ReactCompositeComponent,ReactDOMComponent,ReactDOMTextComponent。稍后我会详细解释缘由。性能
让咱们继续组件的实例化。咱们会建立一个ReactCompositeComponent的实例,可是,
这个实例并非由于咱们将<ExampleApplication/>放入ReactDOM.render中而后才生成的。React老是从TopLevelWrapper里开始渲染一个组件树。它几乎是一个纯包装组件,它的render方法(组件的render方法)将会返回<ExampleApplication/>。代码以下:优化
//src\renderers\dom\client\ReactMount.js#277 TopLevelWrapper.prototype.render = function () { return this.props.child; };
根据以上代码,很显然只有一个TopLevelWrapper的实例被建立了,除此以外就没有其它的了。在继续下一步以前,咱们看下如下内容:
DOM内嵌验证
几乎每次内嵌组件渲染时,它们都会被一个专门用来作HTML验证的模块--validateDOMNesting--来验证结构是否合法。所谓的DOM内嵌验证是指校验子模块和父模块的标签层次。好比,若是父组件的标签是<select>,子组件的标签只能是如下中的一个:optino,optgroup,#text。 这些规则都是在 https://html.spec.whatwg.org/... 被定义的。你极可能已经看到过这个模块的工做成果,它会产生以下的错误提醒:<div>不能为<p>的后代出现(<div> cannot appear as a descendant of <p> .)
好了,让咱们回想下以前的内容,而后再回顾下挂载相关的流程图。 Part0的部分就是这些。
(未完待续)