美文网首页react
setState分析

setState分析

作者: 你的时间非常值钱 | 来源:发表于2019-07-25 23:43 被阅读0次

组件更新方法

1.setState
2.replaceState(后面废弃)
3.forceUpdate

setState
ReactComponent.prototype.setState = function(particalState, callback) {
  this.updater.enqueueSetState(this, particalState);
  if (callback) {
   this.updater.enqueueCallback(this, callback, 'setState');
  }
};

enqueueSetState

  enqueueSetState: function(publicInstance, partialState) {
    ...

    var internalInstance = getInternalInstanceReadyForUpdate(
      publicInstance,
      'setState'
    );

    if (!internalInstance) {
      return;
    }

    var queue =
      internalInstance._pendingStateQueue ||
      (internalInstance._pendingStateQueue = []);
    queue.push(partialState);

    enqueueUpdate(internalInstance);
  },

enqueueCallback

enqueueCallback: function(publicInstance, callback, callerName) {
    ReactUpdateQueue.validateCallback(callback, callerName);
    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);

    ...
    if (!internalInstance) {
      return null;
    }

    if (internalInstance._pendingCallbacks) {
      internalInstance._pendingCallbacks.push(callback);
    } else {
      internalInstance._pendingCallbacks = [callback];
    }
    ...
    enqueueUpdate(internalInstance);
  },

两个方法共同点:
1.getInternalInstanceReadyForUpdate,获取ReactCompositeComponentWrapper实例
2.enqueueSetState将新state推入_pendingStateQueue队列,enqueueCallback将callback推进_pendingCallbacks队列
3.最后都调用enqueueUpdate方法


enqueueUpdate

function enqueueUpdate(internalInstance) {
  ReactUpdates.enqueueUpdate(internalInstance);
}
...
function enqueueUpdate(component) {
  ensureInjected();

  ...

  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }

  dirtyComponents.push(component);
  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}

isBatchingUpdates决定了是否处于事务中,是就将component推入dirtyComponent,不是就将自己(enqueueUpdate)放入事务执行


function ensureInjected() {
  invariant(
    ReactUpdates.ReactReconcileTransaction && batchingStrategy,
    'ReactUpdates: must inject a reconcile transaction class and batching ' +
    'strategy'
  );
}

在ensureInjected里看到, ReactUpdates依赖了ReactUpdates.ReactReconcileTransactionbatchingStrategy
ReactReconcileTransaction:处理生命周期相关更新工作
batchingStrategy:处理批量更新

React中的事务

/**
 * <pre>
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | 
 *                    | +---+ +---+   +---------+   +---+ +---+ | 
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | 
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * </pre>
 */
// 事务结束时将isBatchingUpdates 设为false
var RESET_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: function() {
    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
  },
};

// 事务结束时执行flushBatchedUpdates,在事务的close阶段运行runBatchedUpdates来update,close,执行顺序是FLUSH_BATCHED_UPDATES到RESET_BATCHED_UPDATES 
var FLUSH_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates),
};

// wrapper组合
var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];

function ReactDefaultBatchingStrategyTransaction() {
  this.reinitializeTransaction(); // 在Mixin的里的初始化方法
}

Object.assign(
  ReactDefaultBatchingStrategyTransaction.prototype,
  Transaction.Mixin, // 包括initializeAll,closeAll,perform等逻辑
  {
    getTransactionWrappers: function() {
      return TRANSACTION_WRAPPERS;
    },
  }
);

var transaction = new ReactDefaultBatchingStrategyTransaction();
流程.png

flushBatchedUpdates

var flushBatchedUpdates = function() {
  ...
  while (dirtyComponents.length || asapEnqueued) {
    if (dirtyComponents.length) {
      var transaction = ReactUpdatesFlushTransaction.getPooled();
      transaction.perform(runBatchedUpdates, null, transaction);
      ReactUpdatesFlushTransaction.release(transaction);
    }

    if (asapEnqueued) {
      asapEnqueued = false;
      var queue = asapCallbackQueue;
      asapCallbackQueue = CallbackQueue.getPooled();
      queue.notifyAll();
      CallbackQueue.release(queue);
    }
  }
  ...
};

runBatchedUpdates

function runBatchedUpdates(transaction) {
  var len = transaction.dirtyComponentsLength;
  ...

  dirtyComponents.sort(mountOrderComparator);
  updateBatchNumber++;

  for (var i = 0; i < len; i++) {
    var component = dirtyComponents[i];
    var callbacks = component._pendingCallbacks;
    component._pendingCallbacks = null;
    ...

    ReactReconciler.performUpdateIfNecessary(
      component,
      transaction.reconcileTransaction,
      updateBatchNumber
    );
    ...

  }
}

遍历所有dirtyComponents,通过mountOrderComparator排序,将callback放入事务队列

 performUpdateIfNecessary: function(
    internalInstance,
    transaction,
    updateBatchNumber
  ) {
    ...
    internalInstance.performUpdateIfNecessary(transaction);
    ...
  },

发现调用的是internalInstance的方法,它属于ReactCompositeComponentWrapper,在ReactCompositeComponent里找

performUpdateIfNecessary: function(transaction) {
    if (this._pendingElement != null) {
      ReactReconciler.receiveComponent(
        this,
        this._pendingElement,
        transaction,
        this._context
      );
    } else if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
      this.updateComponent(
        transaction,
        this._currentElement,
        this._currentElement,
        this._context,
        this._context
      );
    } else {
      this._updateBatchNumber = null;
    }
  },

判断如果element级别的比较不同就会调用receiveComponent,_pendingStateQueue 和_pendingForceUpdate情况下,调用updateComponent

updateComponent

updateComponent: function(
    transaction,
    prevParentElement,
    nextParentElement,
    prevUnmaskedContext,
    nextUnmaskedContext
  ) {
    var inst = this._instance;
    ...

    var willReceive = false;
    var nextContext;
    var nextProps;

    // context检查,如果变化存到nextContext
    if (this._context === nextUnmaskedContext) {
      nextContext = inst.context;
    } else {
      nextContext = this._processContext(nextUnmaskedContext);
      willReceive = true;
    }

    nextProps = nextParentElement.props;

    if (prevParentElement !== nextParentElement) {
      willReceive = true;
    }

    // 判断props更新,出发componentWillReceiveProps生命周期
    if (willReceive && inst.componentWillReceiveProps) {
      ...
      inst.componentWillReceiveProps(nextProps, nextContext);
      ...
    }
    
   // _processPendingState处理最新state
    var nextState = this._processPendingState(nextProps, nextContext);
    var shouldUpdate = true;
    //  是否执行生命周期shouldComponentUpdate
    if (!this._pendingForceUpdate && inst.shouldComponentUpdate) {
      ...
      shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
      ...
    }

    ...

    this._updateBatchNumber = null;
   // 是否更新虚拟DOM,是就通过_performComponentUpdate更新,否则只改变值
    if (shouldUpdate) {
      this._pendingForceUpdate = false;
      // 更新 `this.props`, `this.state` 和`this.context`.
      this._performComponentUpdate(
        nextParentElement,
        nextProps,
        nextState,
        nextContext,
        transaction,
        nextUnmaskedContext
      );
    } else {
      this._currentElement = nextParentElement;
      this._context = nextUnmaskedContext;
      inst.props = nextProps;
      inst.state = nextState;
      inst.context = nextContext;
    }
  },
_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 = assign({}, replace ? queue[0] : inst.state);
    for (var i = replace ? 1 : 0; i < queue.length; i++) {
      var partial = queue[i];
      assign(
        nextState,
        typeof partial === 'function' ?
          partial.call(inst, nextState, props, context) :
          partial
      );
    }

    return nextState;
  },

setState第一个参数除了可以是对象,也可以是函数,通过函数入参可以得到最新state,props和context

相关文章

网友评论

    本文标题:setState分析

    本文链接:https://www.haomeiwen.com/subject/rwuqrctx.html