【Under-the-hood-ReactJS-Part3】React源码解读

接上文,git

React流程图:
https://bogdan-lyashenko.gith...github

挂载

componentMount是咱们重点关注对象之一。 这个方法最重要的部分就是ReactCompositeComponent.mountComponent.
若是你还有印象,我提到过第一个被压入到组件树里的组件是TopLevelWrapper(React内部类)。在mountComponent中,咱们将挂载它。
可是,这个内部类是一个空的包装类。对于调试来讲毫无心义,它彻底不影响流程。因此,咱们暂且跳过它,先对它的子组件进行研究。app

挂载一个组件树的过程大体以下:挂载父亲组件,而后挂载它的子组件,而后是子组件的子组件,以此类推。当TopLevelWrapper挂载后,它的子组件(ReactCompositeComponent,负责管理ExampleApplication)也会进入到相同的步骤。svg

咱们回到ReactCompoiteComponent一探究竟。这里面有一些关键点须要注意,接下去咱们会详细的讨论里面的逻辑。函数

赋值实例更新器

流程图中 transaction.getUpdateQueue()返回的对象updateQueue,其实就是ReactUpdateQueue模块。那么会为何在这里要赋值updateQueue呢?这是由于ReactCompositeComponent(咱们正在研究的类)是各个平台都须要使用的,可是updateQueue则在不一样平台有不一样实现,因此须要咱们动态的在挂载过程当中根据不一样的平台赋予不一样的值。this

目前咱们并不会使用updateQueue,可是咱们必须了解的是,updateQueue很是很是重要,大名鼎鼎的setState方法就会使用到这个updateQueue。调试

在这个阶段,除了对updateQueue的赋值,还会有组件实例(自定义组件)被props,context,refs扩展的过程。code

看下以下代码:component

// \src\renderers\shared\stack\reconciler\ReactCompositeComponent.js#255
// These should be set up in the constructor, but as a convenience for
// simpler class abstractions, we set them up after the fact.
inst.props = publicProps;
inst.context = publicContext;
inst.refs = emptyObject;
inst.updater = updateQueue;

这个步骤以后,就能够经过相似this.props的方式来让实例获取props等属性了。对象

建立ExampleApplication实例

在流程图中,经过调用_constructComponent方法和其余几个构造方式,一个新的ExampleApplication实例就被建立出来了。咱们在组件构造函数里写的代码每每也是在这里被调用的。 这里,是咱们本身写的代码第一次真正被React系统调用的地方。

执行初始挂载

如今咱们开始挂载过程,第一件事就是调用componentWillMount(前提固然是若是有组件代码里有指定)。这个方法是咱们目前碰到的第一个生命周期事件钩子。固然,在后面你也会看到componentDidMount方法。在这里,咱们并不直接执行它们,咱们只是将它们押入到事务队列里。它们的真正的执行在很是后面,是在挂载操做完成以后才执行的。你能够在componentWillMount里调用setState方法,而后state会从新计算,可是render方法并不会被调用(若是在这里调用render方法是毫无心义的,由于组件都没挂载到DOM树上呢)

官方文档表达了相似的意思

当挂载事件发生前,componentWillMount方法会被马上调用。它的调用在render方法以前,所以,在这里调用setState不会触发从新渲染(componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state in this method will not trigger a re-rendering.)

看下源码里是怎么作的

// \src\renderers\shared\stack\reconciler\ReactCompositeComponent.js#476
if (inst.componentWillMount) {
    //..
    inst.componentWillMount();

    // When mounting, calls to `setState` by `componentWillMount` will set
    // `this._pendingStateQueue` without triggering a re-render.
    if (this._pendingStateQueue) {
        inst.state = this._processPendingState(inst.props, inst.context);
    }
}

当state从新计算后,咱们就会调用render方法了,就是咱们在咱们自定义组件里定义的render方法。React又一次使用了咱们的代码。

接下去,咱们将会建立一个React组件实例,嗯,又建立一次。咱们以前已经调用过一次this._instantiateReactComponent了,为何这里又要调用一次呢?这是由于,前一次的调用,是建立一个ExampleApplication组件对应的ReactCompositeComponent实例,如今,咱们则是根据咱们组件的render方法中返回的元素,建立子组件对应的虚拟DOM实例。在咱们的列子中,render方法返回了一个div,因此,虚拟DOM建立一个ReactDOMComponent的实例。当这个实例建立后,咱们会又一次调用ReactReconciler.mountComponent方法,但此次是一个建立内部实例但过程,咱们传递的是一个ReactDOMComponent的实例。 而后,继续调用它的mountComponent方法。。。(未完待续)

相关文章
相关标签/搜索