組件更新方法
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.ReactReconcileTransaction和batchingStrategy
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();

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