Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReactCompositeComponent源码学习 #13

Open
hitobear opened this issue Mar 8, 2018 · 0 comments
Open

ReactCompositeComponent源码学习 #13

hitobear opened this issue Mar 8, 2018 · 0 comments

Comments

@hitobear
Copy link
Owner

hitobear commented Mar 8, 2018

  • 源码地址: src/renderers/shared/stack/reconciler/ReactReconciler.js
  • 作用:用户自定义组件的基础包装类,包含一系列组件挂载,卸载的方法。
  • 挂载入口:batchedUpdates->batchedMountComponentIntoNode->mountComponentIntoNode->ReactReconciler.mountComponent-> internalInstance.mountComponent

mountComponent方法

mountComponent: function(
    transaction,
    hostParent,
    hostContainerInfo,
    context,
  ) {
    this._context = context;
    this._mountOrder = nextMountID++;//模块全局属性nextMountID,赋值给实例的私有属性。
    this._hostParent = hostParent;
    this._hostContainerInfo = hostContainerInfo;

    var publicProps = this._currentElement.props;//这里的_currentElement指的TopLevelWrapper
类型的元素,它的props中的child属性对象的是真正的元素,详见[React源码学习-新建一个组件](https://github.com/hitobear/blog/issues/9)
    var publicContext = this._processContext(context);

    var Component = this._currentElement.type;

    var updateQueue = transaction.getUpdateQueue();

    // Initialize the public class
    var doConstruct = shouldConstruct(Component);
    var updateQueue = transaction.getUpdateQueue();//作为参数传给实例构造使用,什么用?
    var inst = this._constructComponent(
      doConstruct,
      publicProps,
      publicContext,
      updateQueue,
    );
    var renderedElement;
 // Support functional components
    if (!doConstruct && (inst == null || inst.render == null)) {
      renderedElement = inst;
    ......
   }
   this._instance = inst;//将真正的组件实例赋值给私有变量_instance
    // Store a reference from the instance back to the internal representation
    ReactInstanceMap.set(inst, this);将组件实例对象和这个包裹对象(ReactCompositeComponent类型的对象)作为key,value存入map
    var initialState = inst.state;
    if (initialState === undefined) {//什么时候不等于undefiend,构造函数中的setState会已经生效了??
      inst.state = initialState = null;
    }
   var markup;
if (inst.unstable_handleError) {
      markup = this.performInitialMountWithErrorHandling(
        renderedElement,
        hostParent,
        hostContainerInfo,
        transaction,
        context,
      );
    } else {
      markup = this.performInitialMount(//执行componentWillMount方法,递归挂载子节点元素
        renderedElement,
        hostParent,
        hostContainerInfo,
        transaction,
        context,
      );
    }
...
if (inst.componentDidMount) {
      if (__DEV__) {
      ......
        });
      } else {
        transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);//执行
//componentDidMount的方法,这里transaction.getReactMountReady是什么?
//enqueue又有什么用?应该是所有子孙的componentDidMount都会在所有组件挂载完后
//依入栈顺序来执行?mountReady就是准备完成挂载?
      }
    }

this._constructComponent->this._constructComponentWithoutOwner

this.this._constructComponent调用的实际是this._constructComponentWithoutOwner,在这个方法中,终于真正的调用了自定义组件的构造函数生成了组件类的一个实例对象,关键代码如下:

 var Component = this._currentElement.type;(//this._currentElement.type就是自定义的组件函数)
if (doConstruct) {
   return new Component(publicProps, publicContext, updateQueue);
} else{
   return Component(publicProps, publicContext, updateQueue);
}

this.performInitialMount

核心逻辑代码如下

performInitialMount: function(
    renderedElement,
    hostParent,
    hostContainerInfo,
    transaction,
    context,
  ) {
    var inst = this._instance;
   if (inst.componentWillMount) {
......
inst.componentWillMount();
......
// When mounting, calls to `setState` by `componentWillMount` will set
// `this._pendingStateQueue` without triggering a re-render. componentWillMount中的setState不会
//触发组件重绘,而是设置_pendingStateQuque变量,设置了之后什么时候生效,render方法的时候就会生效了把?
 if (this._pendingStateQueue) {
        inst.state = this._processPendingState(inst.props, inst.context);
 }
      }
// If not a stateless component, we now rende如果是一个无状态函数组件,renderedElement已经
//有值了,回退查代码
    if (renderedElement === undefined) {
      renderedElement = this._renderValidatedComponent();//执行组件的render()方法,生成的是一个元素对象,和开始ReactDom.render(element,ddd)中的第一个元素是同类
    }
var nodeType = ReactNodeTypes.getType(renderedElement);
    this._renderedNodeType = nodeType;
    var child = this._instantiateReactComponent(
      renderedElement,
      nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */,
    );
//这里this_instantiateReactComponent方法和ReactMount中的instantiateReactComponent方法是同一个,是ReactCompositeComponent的原型被赋值过,详见[新建一个组件-instantiateReactComponent()方法](https://github.com/hitobear/blog/issues/9)
    this._renderedComponent = child;
    //调用instantiate方法后,把下一级元素对象转化成了ReactCompositeComponentWrapper类的对象,和当前对像是同类,进而递归,调用 ReactReconciler.mountComponent(当初第一个渲染的元素的mountComponent方法就是通过这里一步步入栈过来的),其中代代子孙共享的是同一个transatcion变量(这也是为什么transaction要从外层传了?因为从ReactReconciler.mountComponent开始调,所以为了共享一个transaction,必须要在这之前就得到transaction)
    var markup = ReactReconciler.mountComponent(
      child,
      transaction,
      hostParent,
      hostContainerInfo,
      this._processChildContext(context),
      debugID,
    );
return markup;

看上去递归没有尽头,实际上我们只分析了自定义组件的渲染过程,知道string类型的元素(底层dom)为止,递归应该会结束。

this._processPendingState

源码

_processPendingState: function(props, context) {
    var inst = this._instance;
    var queue = this._pendingStateQueue;//待合并的状态
    var replace = this._pendingReplaceState;//替换状态标志,真表示激活,对原状态进行替换,
//假表示未激活,进行状态合并
    this._pendingReplaceState = false;//默认情况下,没有激活替换状态
    this._pendingStateQueue = null;

    if (!queue) {//队列里没有值,说明没有待合并的,则直接返回原状态即可
      return inst.state;
    }

    if (replace && queue.length === 1) {
      return queue[0];//替换标记激活,且队列里只有一个值的话,无需合并,直接返回新值即可
    }

    var nextState = Object.assign({}, replace ? queue[0] : inst.state);//剩下的情况,根据replace标记而定
//初始值,要么是原状态值`inst.state`,要么是queue[0],
    for (var i = replace ? 1 : 0; i < queue.length; i++) {
      var partial = queue[i];
      Object.assign(
        nextState,
        typeof partial === 'function'
          ? partial.call(inst, nextState, props, context)
          : partial,
      );
    }

    return nextState;
  },

疑问

  • pendingStateQueue一开始是null,什么时候有值得,setState方法?setState方法怎么发挥作用的?
  • transaction.getUpdateQueue用来干嘛的?它的返回结果还传给了组件的构造函数作为第三个参数,又什么用?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant