React中updateContainerImpl方法更新容器源碼解析
概覽
在ReactDOMRoot的render和unmount方法中均調(diào)用了updateContainerImpl方法,該方法是React中更新容器的核心方法,負(fù)責(zé)創(chuàng)建和調(diào)度更新。
源碼分析
updateContainerImpl
updateContainerImpl方法源碼實現(xiàn)如下:
function updateContainerImpl(
rootFiber, //根Fiber節(jié)點
lane, // 更新優(yōu)先級
element, //要渲染的React元素
container, // Fiber根節(jié)點容器
parentComponent, // 父組件
callback // 更新完成后的回調(diào)函數(shù)
) {
// 獲取子樹的上下文,會返回一個空對象
parentComponent = getContextForSubtree(parentComponent);
// 若Fiber根節(jié)點容器上下文為空,則設(shè)置其為獲取到的上下文(空對象);否則設(shè)置待處理的上下文為空對象
null === container.context
? (container.context = parentComponent)
: (container.pendingContext = parentComponent);
// 根據(jù)優(yōu)先級車道創(chuàng)鍵更新對象
container = createUpdate(lane);
// 將要渲染的React元素作為更新對像的載荷
container.payload = { element: element };
// 若回調(diào)未定義,則設(shè)為null,否則保留原值
callback = void 0 === callback ? null : callback;
// 若回調(diào)不為null,則將其設(shè)為更新對象的callback屬性值
null !== callback && (container.callback = callback);
// 將更新對象添加到Fiber節(jié)點的更新隊列,并獲取FiberRoot
element = enqueueUpdate(rootFiber, container, lane);
// 判斷 若返回的更新對象不為null,則調(diào)度更新
null !== element &&
(scheduleUpdateOnFiber(element, rootFiber, lane),
entangleTransitions(element, rootFiber, lane));
}
createUpdate
createUpdate接受一個參數(shù)車道優(yōu)先級(lane),返回一個更新對象,其對象類型為Update,Update會被放入更新隊列中等待調(diào)度執(zhí)行,其優(yōu)先級為參數(shù)lane,tag為UpdateState:0,其實現(xiàn)如下:
function createUpdate(lane){
return {
lane: lane, // 更新優(yōu)先級
tag: UpdateState, // 其值為1 ,表示更新類型
payload: null, // 更新載荷
callback: null, // 回調(diào)函數(shù)
next: null // 指向下一個更新
}
}
enqueueUpdate
enqueueUpdate方法用于將更新對象加入Fiber節(jié)點的更新隊列,其源碼實現(xiàn)如下:
function enqueueUpdate(fiber, update, lane) {
// 獲取Fiber節(jié)點上的更新隊列updateQueue
var updateQueue = fiber.updateQueue;
// 若更新隊列為空,則返回null,此時Fiber節(jié)點已被卸載
if (null === updateQueue) return null;
// 獲取共享隊列
updateQueue = updateQueue.shared;
// 檢查是否是渲染更新階段
if (0 !== (executionContext & 2)) {
// 獲取共享隊列的最后一個節(jié)點
var pending = updateQueue.pending;
// 判斷最后一個節(jié)點是否為空
null === pending
? (update.next = update) // 將更新對象update的next指向自身
: ((update.next = pending.next), (pending.next = update)); //否則將更新對象的next指向最后一個節(jié)點的next,并且將最后一個節(jié)點的next指向更新對象,即將更新對象插入到環(huán)形鏈表的末尾
// 更新pending指針
updateQueue.pending = update;
// 從Fiber節(jié)點中獲取FiberRoot
update = getRootForUpdatedFiber(fiber);
// 標(biāo)記fiber節(jié)點中的優(yōu)先級
markUpdateLaneFromFiberToRoot(fiber, null, lane);
// 最后返回FiberRoot
return update;
}
// 若不是渲染更新階段,則依次執(zhí)行enqueueUpdate$1,getRootForUpdatedFiber,最后返回getRootForUpdatedFiber的結(jié)果FiberRoot
// 調(diào)用enqueueUpdate$1方法就是將相關(guān)參數(shù)放到并發(fā)隊列concurrentQueues中
enqueueUpdate$1(fiber, updateQueue, update, lane);
return getRootForUpdatedFiber(fiber);
}
getRootForUpdatedFiber
Fiber節(jié)點的return始終是指向父節(jié)點,因此通過不斷追溯return可以找到根節(jié)點;
function getRootForUpdatedFiber(sourceFiber) {
// 判斷某計數(shù)器,暫且不提
if (50 < nestedUpdateCount)
throw (
((nestedUpdateCount = 0),
(rootWithNestedUpdates = null),
Error(formatProdErrorMessage(185)))
);
for (var parent = sourceFiber.return; null !== parent; )
(sourceFiber = parent), (parent = sourceFiber.return);
// 判斷當(dāng)前Fiber節(jié)點的根節(jié)點類型是否為HostRoot,若是,則返回其DOM元素,否則返回null
return 3 === sourceFiber.tag ? sourceFiber.stateNode : null;
}
scheduleUpdateOnFiber
調(diào)用enqueueUpdate方法更新相關(guān)隊列后,會拿到FiberRoot,若FiberRoot不為null,則調(diào)用scheduleUpdateOnFiber進(jìn)行調(diào)度更新。
entangleTransitions
entangleTranslations方法用于糾纏過渡更新,主要有3個作用:
- 將當(dāng)前更新與正在進(jìn)行的過渡更新糾纏
- 確保過渡更新的正確順序
- 處理并發(fā)模式下的更新沖突
到此這篇關(guān)于React中updateContainerImpl方法更新容器源碼解析的文章就介紹到這了,更多相關(guān)React updateContainerImpl更新容器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react中使用echarts,并實現(xiàn)tooltip循環(huán)輪播方式
這篇文章主要介紹了react中使用echarts,并實現(xiàn)tooltip循環(huán)輪播方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
react render props模式實現(xiàn)組件復(fù)用示例
本文主要介紹了react render props模式實現(xiàn)組件復(fù)用示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

