




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
第react組件的創(chuàng)建與更新實現(xiàn)流程詳解目錄React源碼執(zhí)行流程圖legacyRenderSubtreeIntoContainerlegacyCreateRootFromDOMContainercreateLegacyRootReactDOMBlockingRootcreateRootImplcreateContainercreateFiberRootcreateHostRootFibercreateFiberupdateContainer總結(jié)這一章節(jié)就來講講ReactDOM.render()方法的內(nèi)部實現(xiàn)與流程吧。
因為初始化的源碼文件部分所涵蓋的內(nèi)容很多,包括創(chuàng)建渲染、更新渲染、Fiber樹的創(chuàng)建與diff,element的創(chuàng)建與插入,還包括一些優(yōu)化算法,所以我就整個的React執(zhí)行流程畫了一個簡單的示意圖。
React源碼執(zhí)行流程圖
從圖中我們很清晰的看到ReactDOM.render()之后我們的組件具體干了什么事情,那么我們進入源碼文件一探究竟吧。
//packages/react-dom/src/client/ReactDOMLegacy.js
exportfunctionrender(
element:React$Elementany,//經(jīng)過babel解析后的element
container:Container,//根組件節(jié)點:document.getElementById('root')..
callback:Function,//回調(diào)
//做合法容器的驗證(根組件)
invariant(
isValidContainer(container),
'TargetcontainerisnotaDOMelement.',
//開發(fā)模式下
if(__DEV__){
constisModernRoot=
isContainerMarkedAsRoot(container)
container._reactRootContainer===undefined;
if(isModernRoot){
console.error(
'YouarecallingReactDOM.render()onacontainerthatwaspreviously'+
'passedtoReactDOM.createRoot().Thisisnotsupported.'+
'Didyoumeantocallroot.render(element)',
//返回legacyRenderSubtreeIntoContainer
returnlegacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
所以當(dāng)前render函數(shù)僅僅只是做了部分邏輯,閱讀React源碼,給你一個直觀的感受就是他拆分的顆粒度非常的細(xì),很多重復(fù)命名的函數(shù),可能是見名知意的變量名只有那么幾個常見的組合吧,這也是React作者的用心良苦吧。
追根究底我們還是得看一看legacyRenderSubtreeIntoContainer究竟干了些不為人知的事情呢
legacyRenderSubtreeIntoContainer
functionlegacyRenderSubtreeIntoContainer(
parentComponent:React$Componentany,any,//父級組件
children:ReactNodeList,//當(dāng)前元素
container:Container,//容器eg:getElementById('root')
forceHydrate:boolean,callback:Function,
if(__DEV__){
topLevelUpdateWarnings(container);
warnOnInvalidCallback(callback===undefinednull:callback,'render');
//TODO:Without`any`type,Flowsays"Propertycannotbeaccessedonany
//memberofintersectiontype."Whyyyyyy.
letroot:RootType=(container._reactRootContainer:any);
letfiberRoot;
//如果有根組件,表示不是初始化渲染,則走下面的批量更新
//沒有根組件,那么就要去創(chuàng)建根組件了
if(!root){
//初始化掛載
root=container._reactRootContainer=legacyCreateRootFromDOMContainer(
container,
forceHydrate,
fiberRoot=root._internalRoot;
if(typeofcallback==='function'){
constoriginalCallback=callback;
callback=function(){
constinstance=getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
//不必要的批量更新
unbatchedUpdates(()={
updateContainer(children,fiberRoot,parentComponent,callback);
}else{
fiberRoot=root._internalRoot;
if(typeofcallback==='function'){
constoriginalCallback=callback;
callback=function(){
constinstance=getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
//批量更新
updateContainer(children,fiberRoot,parentComponent,callback);
returngetPublicRootInstance(fiberRoot);
}
有根節(jié)點的情況下,我們判定為非首次渲染狀態(tài),執(zhí)行updateContainer沒有根節(jié)點的情況下,我們判定為首次渲染,接著去創(chuàng)建根節(jié)點,執(zhí)行l(wèi)egacyCreateRootFromDOMContainer,拿到了root之后,我們會去觸發(fā)執(zhí)行updateContainer
legacyCreateRootFromDOMContainer
functionlegacyCreateRootFromDOMContainer(
container:Container,//容器
forceHydrate:boolean,//value:false
):RootType{
constshouldHydrate=
forceHydrate||shouldHydrateDueToLegacyHeuristic(container);
//Firstclearanyexistingcontent.
if(!shouldHydrate){
letwarned=false;
letrootSibling;
while((rootSibling=container.lastChild)){
if(__DEV__){
if(
!warned
rootSibling.nodeType===ELEMENT_NODE
(rootSibling:any).hasAttribute(ROOT_ATTRIBUTE_NAME)
warned=true;
console.error(
'render():TargetnodehasmarkuprenderedbyReact,butthere'+
'areunrelatednodesaswell.Thisismostcommonlycausedby'+
'white-spaceinsertedaroundserver-renderedmarkup.',
container.removeChild(rootSibling);
if(__DEV__){
if(shouldHydrate!forceHydrate!warnedAboutHydrateAPI){
warnedAboutHydrateAPI=true;
console.warn(
'render():CallingReactDOM.render()tohydrateserver-renderedmarkup'+
'willstopworkinginReactv18.ReplacetheReactDOM.render()call'+
'withReactDOM.hydrate()ifyouwantReacttoattachtotheserverHTML.',
//關(guān)注createLegacyRoot
returncreateLegacyRoot(
container,
shouldHydrate
hydrate:true,
:undefined,
}
createLegacyRoot
exportfunctioncreateLegacyRoot(
container:Container,//容器
options:RootOptions,
):RootType{
//關(guān)注ReactDOMBlockingRoot
returnnewReactDOMBlockingRoot(container,LegacyRoot,options);
}
ReactDOMBlockingRoot
functionReactDOMBlockingRoot(
container:Container,//容器
tag:RootTag,//LegacyRoot=0;BlockingRoot=1;ConcurrentRoot=2;
options:void|RootOptions,
this._internalRoot=createRootImpl(container,tag,options);
}
我們在這里看到this._internalRoot出來了,因為在先前這個值會給到fiberRoot,所以我們再去看一看這個_internalRoot是怎么創(chuàng)建出來的相關(guān)參考視頻講解:進入學(xué)習(xí)
createRootImpl
functioncreateRootImpl(
container:Container,tag:RootTag,options:void|RootOptions,
//TagiseitherLegacyRootorConcurrentRoot
consthydrate=options!=nulloptions.hydrate===true;
consthydrationCallbacks=
(options!=nulloptions.hydrationOptions)||null;
constmutableSources=
(options!=null
options.hydrationOptions!=null
options.hydrationOptions.mutableSources)||
null;
//關(guān)注createContainer
constroot=createContainer(container,tag,hydrate,hydrationCallbacks);
markContainerAsRoot(root.current,container);
constcontainerNodeType=container.nodeType;
if(enableEagerRootListeners){
constrootContainerElement=
container.nodeType===COMMENT_NODEcontainer.parentNode:container;
listenToAllSupportedEvents(rootContainerElement);
}else{
if(hydratetag!==LegacyRoot){
constdoc=
containerNodeType===DOCUMENT_NODE
container
:container.ownerDocument;
//WeneedtocastthisbecauseFlowdoesn'twork
//withthehoistedcontainerNodeType.Ifweinline
//it,thenFlowdoesn'tcomplain.Weintentionally
//hoistittoreducecode-size.
eagerlyTrapReplayableEvents(container,((doc:any):Document));
}elseif(
containerNodeType!==DOCUMENT_FRAGMENT_NODE
containerNodeType!==DOCUMENT_NODE
ensureListeningTo(container,'onMouseEnter',null);
if(mutableSources){
for(leti=0;imutableSources.length;i++){
constmutableSource=mutableSources[i];
registerMutableSourceForHydration(root,mutableSource);
//關(guān)注root
returnroot;
}
見名知意關(guān)注createContainer為創(chuàng)建容器,看其源碼
createContainer
//packages/react-reconciler/src/ReactFiberReconciler.old.js
exportfunctioncreateContainer(
containerInfo:Container,//容器
tag:RootTag,//LegacyRoot=0;BlockingRoot=1;ConcurrentRoot=2;
hydrate:boolean,hydrationCallbacks:null|SuspenseHydrationCallbacks,
):OpaqueRoot{
//關(guān)注createFiberRoot
returncreateFiberRoot(containerInfo,tag,hydrate,hydrationCallbacks);
}
createFiberRoot
exportfunctioncreateFiberRoot(
containerInfo:any,tag:RootTag,hydrate:boolean,hydrationCallbacks:null|SuspenseHydrationCallbacks,
):FiberRoot{
constroot:FiberRoot=(newFiberRootNode(containerInfo,tag,hydrate):any);
if(enableSuspenseCallback){
root.hydrationCallbacks=hydrationCallbacks;
//關(guān)注createHostRootFiber
constuninitializedFiber=createHostRootFiber(tag);
root.current=uninitializedFiber;
uninitializedFiber.stateNode=root;
//初始化更新隊列
initializeUpdateQueue(uninitializedFiber);
returnroot;
}
關(guān)注root.current、uninitializedFiber.stateNode這兩個玩意兒,后面有大作用,我們還是看看createHostRootFiber吧
createHostRootFiber
exportfunctioncreateHostRootFiber(tag:RootTag):Fiber{
letmode;
if(tag===ConcurrentRoot){
mode=ConcurrentMode|BlockingMode|StrictMode;
}elseif(tag===BlockingRoot){
mode=BlockingMode|StrictMode;
}else{
mode=NoMode;
if(enableProfilerTimerisDevToolsPresent){
//AlwayscollectprofiletimingswhenDevToolsarepresent.
//ThisenablesDevToolstostartcapturingtimingatanypoint–
//Withoutsomenodesinthetreehavingemptybasetimes.
mode|=ProfileMode;
returncreateFiber(HostRoot,null,null,mode);
}
一眼望去這里便是對tag的處理,到了后面便是去創(chuàng)建fiber節(jié)點
createFiber
constcreateFiber=function(
tag:WorkTag,pendingProps:mixed,key:null|string,mode:TypeOfMode,
):Fiber{
//$FlowFixMe:theshapesareexactherebutFlowdoesn'tlikeconstructors
returnnewFiberNode(tag,pendingProps,key,mode);
};
那么主角出來了,就是我們的FiberNode,這里才走完初始化的創(chuàng)建流程,
所以大致的流程就是上面的圖里畫的那樣子,創(chuàng)建流程我們就告一段落,那我們再去看看更新的流程是怎么玩的。
我們知道除了ReactDOM.render()會觸發(fā)更新流程之外,我們還有setState、強制更新、hooks里面的setXxxx等等手段可以觸發(fā)更新,所謂setState那么不正好是我們Component原型上掛的方法嘛。我們回顧一下Component,那些更新都是調(diào)用了updater觸發(fā)器上的方法,那么我們?nèi)タ匆幌逻@個東西。
constclassComponentUpdater={
isMounted,
//setState
enqueueSetState(inst,payload,callback){
constfiber=getInstance(inst);
consteventTime=requestEventTime();//獲取更新觸發(fā)的時間
constlane=requestUpdateLane(fiber);//獲取任務(wù)優(yōu)先級
//根據(jù)更新觸發(fā)時間+更新優(yōu)先級來創(chuàng)建更新任務(wù)對象
constupdate=createUpdate(eventTime,lane);//創(chuàng)建更新任務(wù)對象
//constupdate:Update*={
//eventTime,//更新時間
//lane,//優(yōu)先級
//tag:UpdateState,//更新類型:0更新,1替換。,2強制替換,3捕獲型更新
//payload:null,//需要更新的內(nèi)容
//callback:null,//更新完后的回調(diào)
//next:null,//指向下一個更新
//};
//把內(nèi)容填上
update.payload=payload;
if(callback!==undefinedcallback!==null){
if(__DEV__){
//開發(fā)環(huán)境下腰給個警告
warnOnInvalidCallback(callback,'setState');
//如果有回調(diào),那么加上回調(diào)
update.callback=callback;
//constupdate:Update*={
//eventTime,//更新時間you
//lane,//優(yōu)先級you
//tag:UpdateState,//更新類型:0更新,1替換。,2強制替換,3捕獲型更新
//payload:null,//需要更新的內(nèi)容you
//callback:null,//更新完后的回調(diào)you
//next:null,//指向下一個更新
//};
enqueueUpdate(fiber,update);//推入更新隊列
scheduleUpdateOnFiber(fiber,lane,eventTime);//調(diào)度
if(__DEV__){
if(enableDebugTracing){
if(fiber.modeDebugTracingMode){
constname=getComponentName(fiber.type)||'Unknown';
logStateUpdateScheduled(name,lane,payload);
if(enableSchedulingProfiler){
markStateUpdateScheduled(fiber,lane);
//replaceState
enqueueReplaceState(inst,payload,callback){
constfiber=getInstance(inst);
consteventTime=requestEventTime();
constlane=requestUpdateLane(fiber);
constupdate=createUpdate(eventTime,lane);
update.tag=ReplaceState;
update.payload=payload;
if(callback!==undefinedcallback!==null){
if(__DEV__){
warnOnInvalidCallback(callback,'replaceState');
update.callback=callback;
enqueueUpdate(fiber,update);
scheduleUpdateOnFiber(fiber,lane,eventTime);
if(__DEV__){
if(enableDebugTracing){
if(fiber.modeDebugTracingMode){
constname=getComponentName(fiber.type)||'Unknown';
logStateUpdateScheduled(name,lane,payload);
if(enableSchedulingProfiler){
markStateUpdateScheduled(fiber,lane);
//forceUpdate
enqueueForceUpdate(inst,callback){
constfiber=getInstance(inst);
consteventTime=requestEventTime();
constlane=requestUpdateLane(fiber);
constupdate=createUpdate(eventTime,lane);
update.tag=ForceUpdate;
if(callback!==undefinedcallback!==null){
if(__DEV__){
warnOnInvalidCallback(callback,'forceUpdate');
update.callback=callback;
enqueueUpdate(fiber,update);
scheduleUpdateOnFiber(fiber,lane,eventTime);
if(__DEV__){
if(enableDebugTracing){
if(fiber.modeDebugTracingMode){
constname=getComponentName(fiber.type)||'Unknown';
logForceUpdateScheduled(name,lane);
if(enableSchedulingProfiler){
markForceUpdateScheduled(fiber,lane);
};
updateContainer
exportfunctionupdateContainer(
element:ReactNodeList,container:OpaqueRoot,parentComponent:React$Componentany,any,callback:Function,
):Lane{
if(__DEV__){
onScheduleRoot(container,element);
constcurrent=container.current;
consteventTime=requestEventTime();
if(__DEV__){
//$FlowExpectedError-jestisn'taglobal,andisn'trecognizedoutsideoftests
if('undefined'!==typeofjest){
warnIfUnmockedScheduler(current);
warnIfNotScopedWithMatchingAct(current);
constlane=requestUpdateLane(current);
if(enableSchedulingProfiler){
markRenderScheduled(lane);
constcontext=getContextForSubtree(parentComponent);
if(container.context===null){
container.context=context;
}else{
container.pendingContext=context;
if(__DEV__){
if(
ReactCurrentFiberIsRendering
ReactCurrentFiber
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 深度分析西方政治考試的熱點問題試題及答案
- 網(wǎng)絡(luò)空間安全的法律法規(guī)試題及答案
- 元宇宙社交平臺虛擬現(xiàn)實社交平臺用戶需求分析與產(chǎn)品優(yōu)化策略報告
- 2025年BIM技術(shù)在建筑項目給排水設(shè)計中的應(yīng)用報告
- 數(shù)字化背景下的公共政策變革試題及答案
- 西方政治制度與文化認(rèn)同的互相影響試題及答案
- 軟考網(wǎng)絡(luò)工程師復(fù)習(xí)策略試題及答案
- 網(wǎng)絡(luò)流量管理的實踐經(jīng)驗與試題及答案
- 自我提升目標(biāo)的設(shè)定與達(dá)成策略試題及答案
- 軟件測試的風(fēng)險控制方法試題及答案
- 家具供貨結(jié)算協(xié)議書
- 2025年公證員資格考試全國范圍真題及答案
- 高考前2天校長在出征儀式生動員講話與在座的大家分享了3顆心
- 游客自愿離團協(xié)議書
- 熱射病護理試題及答案
- 2024-2025學(xué)年滬教版(五四學(xué)制)七年級英語下學(xué)期考點突破:書面表達(dá)15篇(含答案)
- 小區(qū)中控室面試題及答案
- 交規(guī)考試題庫
- 選擇性必修1 《當(dāng)代國際政治與經(jīng)濟》(主觀題答題模版)
- 量子光子ics在生物醫(yī)學(xué)中的應(yīng)用-全面剖析
- 2025年度手術(shù)室感染控制工作計劃
評論
0/150
提交評論