ReactReconciler

ReactReconciler模块用于发起顶层组件或子组件的挂载、卸载、重绘机制。

 

'use strict';

// 创建、销毁、比对reactElement的refs属性相关
var ReactRef = require('./ReactRef');
var ReactInstrumentation = require('./ReactInstrumentation');

var warning = require('fbjs/lib/warning');

// 创建reactElement的refs属性
function attachRefs() {
  ReactRef.attachRefs(this, this._currentElement);
}

var ReactReconciler = {
  // 将组件绘制到文档中,并执行componentDidMount方法,组件实例添加refs属性
  // 参数internalInstance为用户自定义组件ReactComponent或ReactDomComponent实例
  // 参数transaction为ReactReconcileTransaction实例,用于挂载componentDidMount后置钩子的回调函数
  //    及提供ReactComponent的参数updater,使setState诸方法可用
  // ReactMount模块中调用,用于挂载reactComponent,包括用户自定义组件或ReactDomComponent
  // ReacrCompositeComponent模块中调用,用于挂载已实例化的用户自定义组件下的指定子组件
  mountComponent: function (internalInstance, transaction, hostParent, hostContainerInfo, context, parentDebugID // 0 in production and for roots
  ) {
    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeMountComponent(internalInstance._debugID, internalInstance._currentElement, parentDebugID);
      }
    }

    // 将组件实例转化为DomLazyTree后添加到文档中,并执行componentDidMount方法
    var markup = internalInstance.mountComponent(transaction, hostParent, hostContainerInfo, context, parentDebugID);
    
    // 向ReactReconcileTransaction实例的后置钩子中添加attachRefs回调函数,组件绘制完成后执行
    if (internalInstance._currentElement && internalInstance._currentElement.ref != null) {
      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
    }

    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID);
      }
    }
    return markup;
  },

  // ReactCompositeComponent中,传入ReactReconciler.getHostNode的internalInstance为用户自定义组件的子组件
  // 待更新元素的实例或构造函数不同、需要销毁再创建组件实例时,供_replaceNodeWithMarkup方法替换已挂载在文档的节点
  getHostNode: function (internalInstance) {
    return internalInstance.getHostNode();
  },

  // 卸载组件元素,并移除组件元素的refs属性
  // ReactMount模块中调用,用于卸载reactComponent,包括用户自定义组件或ReactDomComponent
  // ReacrCompositeComponent模块中调用,用于卸载已实例化的用户自定义组件下的指定子组件
  unmountComponent: function (internalInstance, safely) {
    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeUnmountComponent(internalInstance._debugID);
      }
    }

    // 移除组件元素的refs属性
    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);

    // 卸载组件元素
    internalInstance.unmountComponent(safely);

    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onUnmountComponent(internalInstance._debugID);
      }
    }
  },

  // 组件元素的props改变,包含props.children改变,或其context属性改变
  // 调用receiveComponent方法重绘组件元素,更新组件元素的refs属性
  // 上层组件即用户自定义组件的state更新时,引起子组件的props或context变更,子组件可以是用户自定义组件或ReactDomComponent
  //    由上层组件调用ReactReconciler.receiveComponent方法发起
  //    上层组件的ReactReconciler.receiveComponent方法又由ReactReconciler.performUpdateIfNecessary发起
  receiveComponent: function (internalInstance, nextElement, transaction, context) {
    var prevElement = internalInstance._currentElement;

    if (nextElement === prevElement && context === internalInstance._context) {
      return;
    }

    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeUpdateComponent(internalInstance._debugID, nextElement);
      }
    }

    // 判断组件元素的refs属性是否需要更新
    var refsChanged = ReactRef.shouldUpdateRefs(prevElement, nextElement);

    // 移除组件元素的refs属性
    if (refsChanged) {
      ReactRef.detachRefs(internalInstance, prevElement);
    }

    // 更新组件,内部调用render方法重新生成待渲染的元素ReactElement
    // 当internalInstance为用户自定义组件时,其下包含的子节点也将得到更新
    internalInstance.receiveComponent(nextElement, transaction, context);

    // 更新refs属性
    if (refsChanged && internalInstance._currentElement && internalInstance._currentElement.ref != null) {
      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
    }

    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
      }
    }
  },

  // 调用setState、forceUpdate方法重绘组件时触发的流程,用于重绘组件
  performUpdateIfNecessary: function (internalInstance, transaction, updateBatchNumber) {
    // internalInstance._updateBatchNumber把组件添加到脏组件时+1,重绘
    // updateBatchNumber当ReactUpdates.flushBatchedUpdates方法执行时自增1
    // 意义是当组件被添加到脏组件的时候,及须重绘组件,这一过程通常由ReactUpdates.enqueueUpdate方法完成
    if (internalInstance._updateBatchNumber !== updateBatchNumber) {
      process.env.NODE_ENV !== 'production' ? 
        warning(internalInstance._updateBatchNumber == null || 
          internalInstance._updateBatchNumber === updateBatchNumber + 1, 
          'performUpdateIfNecessary: Unexpected batch number (current %s, ' + 'pending %s)', 
          updateBatchNumber, internalInstance._updateBatchNumber) 
        : void 0;
      return;
    }

    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeUpdateComponent(internalInstance._debugID, internalInstance._currentElement);
      }
    }

    // internalInstance包含_pendingElement、_pendingStateQueue、_pendingForceUpdate用以判断更新方式
    // _pendingStateQueue为state数据变化引起,由this.setState方法发起
    // _pendingForceUpdate为调用this.forceUpdate方法发起
    // 子组件通过递归调用ReactReconciler.receiveComponent方法
    internalInstance.performUpdateIfNecessary(transaction);

    if (process.env.NODE_ENV !== 'production') {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
      }
    }
  }

};

module.exports = ReactReconciler;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值