【譯】了解React源代碼-初始渲染(簡單組件)1
【譯】了解React源代碼-初始渲染(簡單組件)2
【譯】了解React源代碼-初始渲染(簡單組件)3
【譯】了解React源代碼-初始渲染(類組件)4
【譯】了解React源代碼-初始渲染(類組件)5
【譯】了解React源代碼-UI更新(事務(wù))6
【譯】了解React源代碼-UI更新(事務(wù))7
【譯】了解React源代碼-UI更新(單個DOM)8
【譯】了解React源代碼-UI更新(DOM樹)9
上次我們討論了核心的Transaction類和ReactDefaultBatchingStrategyTransaction。 實例化不是UI更新中涉及的唯一Transaction,而僅僅是領(lǐng)導(dǎo)者。
在本文中,我們將研究其他Transaction,以及ReactDefaultBatchingStrategyTransaction概述UI更新處理邏輯。
本文中使用的文件:
renderers / shared / stack / reconciler / ReactUpdates.js:
定義flushBatchedUpdates()是本文的切入點方法; 它還定義了ReactUpdatesFlushTransaction,這是我們將要討論的Transaction之一
shared / utils / PooledClass.js:
定義PooledClass以啟用實例池
renderers / dom / client / ReactReconcileTransaction.js:
定義ReactReconcileTransaction,這是我們要討論的另一個Transaction
We start with the
ReactUpdates.flushBatchedUpdates(){last post *8}.
我們從ReactUpdates.flushBatchedUpdates(){上一篇 * 8}開始。
...
var flushBatchedUpdates = function () {
while (dirtyComponents.length || asapEnqueued) {
if (dirtyComponents.length) {
var transaction = ReactUpdatesFlushTransaction.getPooled();
transaction.perform(runBatchedUpdates, null, transaction);
ReactUpdatesFlushTransaction.release(transaction);
}
if (asapEnqueued) { // scr: not applied
...
}
}
};
...
ReactUpdates@renderers/shared/stack/reconciler/ReactUpdates.js
如前所述,它通過啟動一個ReactUpdatesFlushTransaction來處理所有臟組件,該ReactUpdatesFlushTransaction最終將調(diào)用runBatchedUpdates。
PooledClass-維護(hù)實例池
這兩個不常見的方法getPooled()和release()繼承自PooledClass,后者提供了實例池化能力:
a)如果池中沒有分配的實例(在本例中為ReactUpdatesFlushTransaction),則getPooled()創(chuàng)建一個新實例;
b)如果池中存在實例,則getPooled()僅返回該實例;
c)release()不會釋放實例,相反,它只是將實例放回池中。
像任何其他類型的池一樣,此實例池的最終目的是減少多余資源(在這種情況下為內(nèi)存)分配和銷毀的開銷。
回到上面的具體情況:
...
while (dirtyComponents.length || asapEnqueued) {
if (dirtyComponents.length) {
var transaction = ReactUpdatesFlushTransaction.getPooled();
...
僅在第一次執(zhí)行while循環(huán)時才分配ReactUpdatesFlushTransaction實例。 之后,可以直接從池中通過getPooled()獲得實例。
This level of understanding of PooledClass is sufficient for the rest of this post. So feel free to fast travel to the the next section by ctrl-f “ReactUpdatesFlushTransaction”.
對PooledClass的這種理解水平足以滿足本文的其余部分。 因此,可以通過ctrl -f“ ReactUpdatesFlushTransaction”快速進(jìn)入下一部分。
現(xiàn)在我們來看一下它的實現(xiàn):
var PooledClass = {
addPoolingTo: addPoolingTo, // scr: ------> 1)
oneArgumentPooler: (oneArgumentPooler: Pooler), // scr: ------> 2)
...// scr: not used
};
module.exports = PooledClass;
PooledClass@shared/utils/PooledClass.js
1)addPoolingTo()是一種“公共”方法,它將池功能添加到一個類中;
2)oneArgumentPooler()是getPooled()的基礎(chǔ)實現(xiàn)。
接下來,我們看一下addPoolingTo()的函數(shù)體:
...
var DEFAULT_POOL_SIZE = 10;
var DEFAULT_POOLER = oneArgumentPooler;
...
var addPoolingTo = function<T>(
CopyConstructor: Class<T>,
pooler: Pooler,
): Class<T> & {
getPooled(): /* arguments of the constructor */ T,
release(): void,
} {
var NewKlass = (CopyConstructor: any);
NewKlass.instancePool = []; // scr: -------------> 1)
NewKlass.getPooled = pooler || DEFAULT_POOLER; // scr: -------> 2)
if (!NewKlass.poolSize) {
NewKlass.poolSize = DEFAULT_POOL_SIZE; // scr: -------------> 3)
}
NewKlass.release = standardReleaser; // scr: -------------> 4)
return NewKlass;
};
...
addPoolingTo@shared/utils/PooledClass.js
1)instancePool是池;
2)將DEFAULT_POOLER(也稱為oneArgumentPooler)附加到getPooled();
3)將poolSize設(shè)置為10;
4)將standardReleaser()附加到release()。
這就是getPooled()和release()的實現(xiàn)方式:
var oneArgumentPooler = function(copyFieldsFrom) {
var Klass = this;
if (Klass.instancePool.length) { // scr: -----------> 1)
var instance = Klass.instancePool.pop(); // scr: -----------> 1)
Klass.call(instance, copyFieldsFrom);
return instance;
} else {
return new Klass(copyFieldsFrom); // scr: ----------------> 2)
}
};
oneArgumentPooler@shared/utils/PooledClass.js
...
var standardReleaser = function(instance) {
var Klass = this;
...
instance.destructor();
if (Klass.instancePool.length < Klass.poolSize) { // scr: ----> 3)
Klass.instancePool.push(instance); // scr: ----> 3)
}
};
standardReleaser@shared/utils/PooledClass.js
1)對應(yīng)于b),其中
Klass.call(instance, copyFieldsFrom);
使用指定的參數(shù)(copyFieldsFrom)調(diào)用Klass構(gòu)造函數(shù)以初始化啟用池的類; 和
2)對應(yīng)于a); 和
3)對應(yīng)于c)。
最后,我們從外部看如何使用addPoolingTo()(ReactUpdatesFlushTransaction):
...
PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);
...
ReactUpdatesFlushTransaction@renderers/shared/stack/reconciler/ReactUpdates.js
ReactUpdatesFlushTransaction
...
function ReactUpdatesFlushTransaction() {
this.reinitializeTransaction();
this.dirtyComponentsLength = null;
this.callbackQueue = CallbackQueue.getPooled();
this.reconcileTransaction =
ReactUpdates.ReactReconcileTransaction.getPooled( // scr: ---> 2)
/* useCreateElement */ true,
);
}
// scr: --------------------------------------------------------> 1)
Object.assign(ReactUpdatesFlushTransaction.prototype, Transaction, {
getTransactionWrappers: function() {
return TRANSACTION_WRAPPERS; // scr: -----------------------> 3)
},
destructor: function() {
this.dirtyComponentsLength = null;
CallbackQueue.release(this.callbackQueue);
this.callbackQueue = null;
ReactUpdates.ReactReconcileTransaction.release( // scr: ----> 2)
this.reconcileTransaction
);
this.reconcileTransaction = null;
},
perform: function(method, scope, a) {
return Transaction.perform.call(
this,
this.reconcileTransaction.perform, // scr: ---------------> 2)
this.reconcileTransaction,
method,
scope,
a,
);
},
});
...
ReactUpdatesFlushTransaction@renderers/shared/stack/reconciler/ReactUpdates.js
1)是Transaction的另一個實例化,它覆蓋了perform()方法;
2)取代直接調(diào)用ReactUpdate.runBatchedUpdates(回調(diào))的方法,重寫的ReactUpdatesFlushTransaction.perform()嵌套調(diào)用了另一個Transaction(ReactReconcileTransaction)的perform()方法和傳遞方法(即ReactUpdate.runBatchedUpdates())作為其回調(diào)方法。 請注意,ReactReconcileTransaction也已啟用池。
3)TRANSACTION_WRAPPERS定義其前置和后置功能:
...
var NESTED_UPDATES = {
initialize: function() {
this.dirtyComponentsLength = dirtyComponents.length;
},
close: function() {
if (this.dirtyComponentsLength !== dirtyComponents.length) {
dirtyComponents.splice(0, this.dirtyComponentsLength);
flushBatchedUpdates(); // scr: ----------------------> a)
} else {
dirtyComponents.length = 0; // scr: ----------------------> b)
}
},
};
var UPDATE_QUEUEING = { // scr: ------> we omit this wrapper for now
initialize: function() {
this.callbackQueue.reset();
},
close: function() {
this.callbackQueue.notifyAll();
},
};
var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];
...
ReactUpdatesFlushTransaction@renderers/shared/stack/reconciler/ReactUpdates.js
NESTED_UPDATES的initialize()1.5)存儲dirtyComponents的數(shù)量; 其close()3)檢查數(shù)字是否已更改。 如果它們不同{a},則調(diào)用flushBatchedUpdates()來重復(fù)該過程; 或會將dirtyComponents.length設(shè)置回0,然后返回上一級Transaction ReactDefaultBatchingStrategyTransaction {上一篇}。
I will not examine the CallbackQueue related operations (in UPDATE_QUEUEING) and will leave them for later articles when discussing component’s life cycle. *9
我將不討論與CallbackQueue相關(guān)的操作(在UPDATE_QUEUEING中),并將在討論組件的生命周期時將其留給以后的文章。 * 9
回顧一下:

ReactReconcileTransaction
這是另一個Transaction,沒有異常。
var Mixin = {
/**
* @see Transaction
* @abstract
* @final
* @return {array<object>} List of operation wrap procedures.
* TODO: convert to array<TransactionWrapper>
*/
getTransactionWrappers: function() {
return TRANSACTION_WRAPPERS; // scr: -----------------------> 1)
},
// scr: ---------------------> we omit all CallbackQueue s for now
getReactMountReady: function() {
return this.reactMountReady;
},
// scr: ---------------------> we omit all CallbackQueue s for now
getUpdateQueue: function() {
return ReactUpdateQueue;
},
checkpoint: function() { // scr: -----------------------> not used
// reactMountReady is the our only stateful wrapper
return this.reactMountReady.checkpoint();
},
rollback: function(checkpoint) { // scr: ---------------> not used
this.reactMountReady.rollback(checkpoint);
},
// scr: ------------------------------------> for instance pooling
destructor: function() {
CallbackQueue.release(this.reactMountReady);
this.reactMountReady = null;
},
};
Object.assign(ReactReconcileTransaction.prototype, Transaction, Mixin);
// scr: --------------------------------------------------------> 2)
PooledClass.addPoolingTo(ReactReconcileTransaction);
module.exports = ReactReconcileTransaction;
ReactReconcileTransaction@renderers/dom/client/ReactReconcileTransaction.js
1)它的包裝器在TRANSACTION_WRAPPERS中定義;
2)如前所述,此類已啟用池。
接下來我們看一下它的三個包裝:
/**
* Ensures that, when possible, the selection range (currently selected text
* input) is not disturbed by performing the transaction.
*/
var SELECTION_RESTORATION = {
/**
* @return {Selection} Selection information.
*/
initialize: ReactInputSelection.getSelectionInformation,
/**
* @param {Selection} sel Selection information returned from `initialize`.
*/
close: ReactInputSelection.restoreSelection,
};
/**
* Suppresses events (blur/focus) that could be inadvertently dispatched due to
* high level DOM manipulations (like temporarily removing a text input from the
* DOM).
*/
var EVENT_SUPPRESSION = {
/**
* @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
* the reconciliation.
*/
initialize: function() {
var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
ReactBrowserEventEmitter.setEnabled(false);
return currentlyEnabled;
},
/**
* @param {boolean} previouslyEnabled Enabled status of
* `ReactBrowserEventEmitter` before the reconciliation occurred. `close`
* restores the previous value.
*/
close: function(previouslyEnabled) {
ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
},
};
/**
* Provides a queue for collecting `componentDidMount` and
* `componentDidUpdate` callbacks during the transaction.
*/
var ON_DOM_READY_QUEUEING = {
/**
* Initializes the internal `onDOMReady` queue.
*/
initialize: function() {
this.reactMountReady.reset();
},
/**
* After DOM is flushed, invoke all registered `onDOMReady` callbacks.
*/
close: function() {
this.reactMountReady.notifyAll();
},
};
var TRANSACTION_WRAPPERS = [
SELECTION_RESTORATION,
EVENT_SUPPRESSION,
ON_DOM_READY_QUEUEING,
];
ReactReconcileTransaction@renderers/dom/client/ReactReconcileTransaction.js
這里的評論很清楚:
SELECTION_RESTORATION用于在UI更新之前存儲文本字段的焦點狀態(tài)(initialize()),并在(close())之后恢復(fù)狀態(tài)。
EVENT_SUPPRESSION用于存儲啟用事件的切換狀態(tài),并在(initialize())之前臨時禁用事件,并在UI更新(close())之后恢復(fù)狀態(tài)。
Again, I will not examine the CallbackQueue related operations (in ON_DOM_READY_QUEUEING) here and will leave them for later articles when discussing component’s life cycle. *10
同樣,我將不在這里檢查與CallbackQueue相關(guān)的操作(在ON_DOM_READY_QUEUEING中),并將在討論組件的生命周期時將其留給以后的文章。 * 10
重要的是要注意ReactReconcileTransaction依賴于默認(rèn)的Transaction.perform()。 它的回調(diào)是ReactUpdate.runBatchedUpdates,它一直向下傳遞到該級別。
ctrl-f “runBatchedUpdates” to examine its route.
ctrl -f“ runBatchedUpdates”檢查其路由。
這個ReactUpdate.runBatchedUpdates將導(dǎo)致我的下一篇文章的內(nèi)容。
回顧一下:

結(jié)論

(原文鏈接)Understanding The React Source Code - UI Updating (Transactions) VII