setState分析

組件更新方法

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);
  },

兩個(gè)方法共同點(diǎn):
1.getInternalInstanceReadyForUpdate,獲取ReactCompositeComponentWrapper實(shí)例
2.enqueueSetState將新state推入_pendingStateQueue隊(duì)列,enqueueCallback將callback推進(jìn)_pendingCallbacks隊(duì)列
3.最后都調(diào)用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決定了是否處于事務(wù)中,是就將component推入dirtyComponent,不是就將自己(enqueueUpdate)放入事務(wù)執(zhí)行


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

在ensureInjected里看到, ReactUpdates依賴了ReactUpdates.ReactReconcileTransactionbatchingStrategy
ReactReconcileTransaction:處理生命周期相關(guān)更新工作
batchingStrategy:處理批量更新

React中的事務(wù)

/**
 * <pre>
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | 
 *                    | +---+ +---+   +---------+   +---+ +---+ | 
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | 
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * </pre>
 */
// 事務(wù)結(jié)束時(shí)將isBatchingUpdates 設(shè)為false
var RESET_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: function() {
    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
  },
};

// 事務(wù)結(jié)束時(shí)執(zhí)行flushBatchedUpdates,在事務(wù)的close階段運(yùn)行runBatchedUpdates來(lái)update,close,執(zhí)行順序是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,通過(guò)mountOrderComparator排序,將callback放入事務(wù)隊(duì)列

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

發(fā)現(xiàn)調(diào)用的是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級(jí)別的比較不同就會(huì)調(diào)用receiveComponent,_pendingStateQueue 和_pendingForceUpdate情況下,調(diào)用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更新,出發(fā)componentWillReceiveProps生命周期
    if (willReceive && inst.componentWillReceiveProps) {
      ...
      inst.componentWillReceiveProps(nextProps, nextContext);
      ...
    }
    
   // _processPendingState處理最新state
    var nextState = this._processPendingState(nextProps, nextContext);
    var shouldUpdate = true;
    //  是否執(zhí)行生命周期shouldComponentUpdate
    if (!this._pendingForceUpdate && inst.shouldComponentUpdate) {
      ...
      shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
      ...
    }

    ...

    this._updateBatchNumber = null;
   // 是否更新虛擬DOM,是就通過(guò)_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第一個(gè)參數(shù)除了可以是對(duì)象,也可以是函數(shù),通過(guò)函數(shù)入?yún)⒖梢缘玫阶钚聅tate,props和context

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在react中通過(guò) state 以及 setState() 來(lái)控制組件內(nèi)部數(shù)據(jù)的狀態(tài),其實(shí)也可以使用類似全局變量的...
    yoona幻塵閱讀 2,559評(píng)論 0 0
  • 前言 這篇文章主要是為了紀(jì)錄一些自己對(duì)于setState的認(rèn)識(shí)的不斷深入的過(guò)程。我覺(jué)得這過(guò)程對(duì)我自己來(lái)說(shuō)很有價(jià)值,...
    Srtian閱讀 6,128評(píng)論 9 17
  • 在react中,通過(guò)管理狀態(tài)來(lái)實(shí)現(xiàn)對(duì)組件的管理,通過(guò)this.state()來(lái)訪問(wèn)state,通過(guò)this.set...
    青艸止閱讀 1,274評(píng)論 0 1
  • React可以抽象的看成一個(gè)公式:UI = f(state)。函數(shù)f是React和基于React的代碼,傳給函數(shù)的...
    Chasingcar_501閱讀 1,354評(píng)論 0 1
  • 手握柔荑,相攜下樓梯,共看檐前燕銜泥。燕喃呢,齊雙飛!小園棲息,芬芳早自迷,綠上枝頭沐露洗。攜嬌妻,赴花期。
    覓緣人閱讀 364評(píng)論 5 6

友情鏈接更多精彩內(nèi)容