初窺React-4(第一個方法)
阿新 • • 發佈:2021-06-20
從第一個方法開始,來到ReactDOMLegacy.js的render方法,其中最主要呼叫了legacyRenderSubtreeIntoContainer 方法,進入到該方法內部.
functionlegacyRenderSubtreeIntoContainer(parentComponent,children,container,forceHydrate,callback){ { topLevelUpdateWarnings(container); warnOnInvalidCallback$1(callback===undefined?null:callback,'render'); }//TODO:Without`any`type,Flowsays"Propertycannotbeaccessedonany //memberofintersectiontype."Whyyyyyy.varroot=container._reactRootContainer; varfiberRoot;
if(!root){ //Initialmount root=container._reactRootContainer=legacyCreateRootFromDOMContainer(container,forceHydrate); fiberRoot=root._internalRoot;// 1.整個專案的根節點
if(typeofcallback==='function'){ varoriginalCallback=callback;
callback=function(){ varinstance=getPublicRootInstance(fiberRoot); //2.返回fiberNode的DOM節點 originalCallback.call(instance); }; }//Initialmountshouldnotbebatched.
unbatchedUpdates(function(){ updateContainer(children,fiberRoot,parentComponent,callback); }); }else{ fiberRoot=root._internalRoot;
if(typeofcallback==='function'){ var_originalCallback=callback;
callback=function(){ varinstance=getPublicRootInstance(fiberRoot);
_originalCallback.call(instance); }; }//Update
updateContainer(children,fiberRoot,parentComponent,callback); //3.開始REACT的主要工作,裡面包括優先順序入隊,虛擬dom, 雙快取切換,然後commit階段,後面會具體延申,這裡大概瞭解 }
returngetPublicRootInstance(fiberRoot); }
1.fiberRoot的結構(一個FiberRootNode節點):
這裡是獲取FiberRootNode程式碼,可見這裡create了LegacyRoot,實際呼叫ReactFiberReconciler包中的createContainer,抽到底就是new了個FiberRootNode物件出來
function legacyCreateRootFromDOMContainer(container, forceHydrate) { var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container); // First clear any existing content.if (!shouldHydrate) { var warned = false; var rootSibling; while (rootSibling = container.lastChild) { { if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) { warned = true; error('render(): Target node has markup rendered by React, but there ' + 'are unrelated nodes as well. This is most commonly caused by ' + 'white-space inserted around server-rendered markup.'); } } container.removeChild(rootSibling); } } { if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) { warnedAboutHydrateAPI = true; warn('render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + 'will stop working in React v18. Replace the ReactDOM.render() call ' + 'with ReactDOM.hydrate() if you want React to attach to the server HTML.'); } } return createLegacyRoot(container, shouldHydrate ? { hydrate: true } : undefined); }
抽到底(具體屬性用到的時候再看):
function FiberRootNode(containerInfo, tag, hydrate) { this.tag = tag; this.containerInfo = containerInfo; this.pendingChildren = null; this.current = null; this.pingCache = null; this.finishedWork = null; this.timeoutHandle = noTimeout; this.context = null; this.pendingContext = null; this.hydrate = hydrate; this.callbackNode = null; this.callbackPriority = NoLanePriority; this.eventTimes = createLaneMap(NoLanes); this.expirationTimes = createLaneMap(NoTimestamp); this.pendingLanes = NoLanes; this.suspendedLanes = NoLanes; this.pingedLanes = NoLanes; this.expiredLanes = NoLanes; this.mutableReadLanes = NoLanes; this.finishedLanes = NoLanes; this.entangledLanes = NoLanes; this.entanglements = createLaneMap(NoLanes); { this.mutableSourceEagerHydrationData = null; } { this.interactionThreadID = unstable_getThreadID(); this.memoizedInteractions = new Set(); this.pendingInteractionMap = new Map(); } { switch (tag) { case BlockingRoot: this._debugRootType = 'createBlockingRoot()'; break; case ConcurrentRoot: this._debugRootType = 'createRoot()'; break; case LegacyRoot: this._debugRootType = 'createLegacyRoot()'; break; } } }
2.這裡直接返回當前current上面的child.stateNode(跟當前Fiber相關本地狀態,比如瀏覽器環境就是DOM節點
)
function getPublicRootInstance(container) { var containerFiber = container.current; if (!containerFiber.child) { return null; } switch (containerFiber.child.tag) { case HostComponent: //HostComponent和default返回的同樣的東西,因為,getPublicInstance直接返回了傳入的引數
return getPublicInstance(containerFiber.child.stateNode);
default:
return containerFiber.child.stateNode;
} }
3.react的主要工作這裡:
function updateContainer(element, container, parentComponent, callback) { { onScheduleRoot(container, element); } var current$1 = container.current; // React按照事件的緊急程度,把它們劃分成三個等級: // 離散事件(DiscreteEvent):click、keydown、focusin等,這些事件的觸發不是連續的,優先順序為0。 // 使用者阻塞事件(UserBlockingEvent):drag、scroll、mouseover等,特點是連續觸發,阻塞渲染,優先順序為1。 // 連續事件(ContinuousEvent):canplay、error、audio標籤的timeupdate和canplay,優先順序最高,為2。 var eventTime = requestEventTime(); { // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests if ('undefined' !== typeof jest) { warnIfUnmockedScheduler(current$1); warnIfNotScopedWithMatchingAct(current$1); } } var lane = requestUpdateLane(current$1); //計算lane,優先順序,賽車道路 { markRenderScheduled(lane); } var context = getContextForSubtree(parentComponent); if (container.context === null) { container.context = context; } else { container.pendingContext = context; } { if (isRendering && current !== null && !didWarnAboutNestedUpdates) { didWarnAboutNestedUpdates = true; error('Render methods should be a pure function of props and state; ' + 'triggering nested component updates from render is not allowed. ' + 'If necessary, trigger nested updates in componentDidUpdate.\n\n' + 'Check the render method of %s.', getComponentName(current.type) || 'Unknown'); } } //建立更新 var update = createUpdate(eventTime, lane); // Caution: React DevTools currently depends on this property // being called "element". update.payload = { element: element }; callback = callback === undefined ? null : callback; if (callback !== null) { { if (typeof callback !== 'function') { error('render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); } } update.callback = callback; } // 更新入佇列 enqueueUpdate(current$1, update); // update物件建立完成後意味著需要對頁面進行更新,會呼叫scheduleUpdateOnFiber進入排程 scheduleUpdateOnFiber(current$1, lane, eventTime); return lane; }