1mikasa1 / react-demo

0 stars 0 forks source link

React18源码-03root.render #6

Open 1mikasa1 opened 2 years ago

1mikasa1 commented 2 years ago

// 在原型上添加render方法 ReactDOMHydrationRoot.prototype.render = ReactDOMRoot.prototype.render = function (children) { // rootFiberNode实例 var root = this._internalRoot;

if (root === null) { throw new Error('Cannot update an unmounted root.'); }

{ // ... // root绑定的dom元素 var container = root.containerInfo; // ... } } updateContainer(children, root, null, null); };

/**

// 创建一个update 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; } // 将update插入到rootFiber下更新队列的队尾 enqueueUpdate(current$1, update); // 开始调度 var root = scheduleUpdateOnFiber(current$1, lane, eventTime); if (root !== null) { entangleTransitions(root, current$1, lane); } return lane; }

1mikasa1 commented 2 years ago

获取当前事件优先级

function requestUpdateLane(fiber) { // 获取到当前渲染的模式:sync mode(同步模式) 或 concurrent mode(并发模式) var mode = fiber.mode; // 是否为并发模式 if ((mode & ConcurrentMode) === NoMode) { return SyncLane; } else if ( (executionContext & RenderContext) !== NoContext && // workInProgressRootRenderLanes为当前需要更新的fiber的lane值,并且当有更新任务时,该值不为空,同时返回该lane workInProgressRootRenderLanes !== NoLanes ) { return pickArbitraryLane(workInProgressRootRenderLanes); } // todo 检查当前事件是否是过渡优先级, 是则返回一个过渡优先级 var isTransition = requestCurrentTransition() !== NoTransition; if (isTransition) { if ( ReactCurrentBatchConfig$3.transition !== null) { var transition = ReactCurrentBatchConfig$3.transition; if (!transition._updatedFibers) { transition._updatedFibers = new Set(); } transition._updatedFibers.add(fiber); } if (currentEventTransitionLane === NoLane) { // All transitions within the same event are assigned the same lane. currentEventTransitionLane = claimNextTransitionLane(); } return currentEventTransitionLane; } // 当触发react内部的事件时,会调用dispatchDiscreteEvent,更新currentUpdatePriority,这里就是直接来拿到这个变量值 var updateLane = getCurrentUpdatePriority(); if (updateLane !== NoLane) { return updateLane; } // 在react的外部事件中触发的更新事件,触发时为当前事件设置一个优先级 var eventLane = getCurrentEventPriority(); return eventLane; }

1mikasa1 commented 2 years ago

更新队列

// 在更新队列的队尾插入update function enqueueUpdate(fiber, update, lane) { // 在createRoot时生成并挂载到了rootFiber下 var updateQueue = fiber.updateQueue; if (updateQueue === null) { // Only occurs if the fiber has been unmounted. return; } var sharedQueue = updateQueue.shared; if (isInterleavedUpdate(fiber)) { ... } else { // 队列最后一个upate var pending = sharedQueue.pending; // 如果没有则直接作为第一个 if (pending === null) { // This is the first update. Create a circular list. update.next = update; } else { // 队尾的upate.next字段指向他的前一个upate update.next = pending.next; // 更新pending.next,让其始终指向队列的最后一个uptate pending.next = update; } // pending指向队列最后一个update sharedQueue.pending = update; } }

1mikasa1 commented 2 years ago

调度阶段

function scheduleUpdateOnFiber(fiber, lane, eventTime) { console.log('workInProgressRoot', workInProgressRoot) // 判断是否是无限嵌套的update队列,例如render函数里面放setState, checkForNestedUpdates(); // 更新事件优先级,rootFiber更新lanes,子fiber树更新childlanes var root = markUpdateLaneFromFiberToRoot(fiber, lane); // 更新fiberRootNode的pendingLanes markRootUpdated(root, lane, eventTime); if ((executionContext & RenderContext) !== NoLanes && root === workInProgressRoot) { warnAboutRenderPhaseUpdatesInDEV(fiber); // Track lanes that were updated during the render phase } else { // This is a normal update, scheduled from outside the render phase. For // example, during an input event. { if (isDevToolsPresent) { addFiberToLanesMap(root, fiber, lane); } } warnIfUpdatesNotWrappedWithActDEV(fiber); if (root === workInProgressRoot) { // TODO: Consolidate with isInterleavedUpdate check // Received an update to a tree that's in the middle of rendering. Mark // that there was an interleaved update work on this root. Unless the // deferRenderPhaseUpdateToNextBatch flag is off and this is a render // phase update. In that case, we don't treat render phase updates as if // they were interleaved, for backwards compat reasons. if ( (executionContext & RenderContext) === NoContext) { workInProgressRootInterleavedUpdatedLanes = mergeLanes(workInProgressRootInterleavedUpdatedLanes, lane); } if (workInProgressRootExitStatus === RootSuspendedWithDelay) { // The root already suspended with a delay, which means this render // definitely won't finish. Since we have a new update, let's mark it as // suspended now, right before marking the incoming update. This has the // effect of interrupting the current render and switching to the update. // TODO: Make sure this doesn't override pings that happen while we've // already started rendering. markRootSuspended$1(root, workInProgressRootRenderLanes); } } // 这里 ensureRootIsScheduled(root, eventTime); if (lane === SyncLane && executionContext === NoContext && (fiber.mode & ConcurrentMode) === NoMode && // Treat act as if it's inside batchedUpdates, even in legacy mode. !( ReactCurrentActQueue$1.isBatchingLegacy)) { resetRenderTimer(); flushSyncCallbacksOnlyInLegacyMode(); } }

return root; }

1mikasa1 commented 2 years ago

任务调度协调

function ensureRootIsScheduled(root, currentTime) { // 旧任务 var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. // 获取renderLanes。与update.lane有关,但不相同,update.lane是事件的优先级。 var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); ...

// 任务优先级,即renderLanes对应的lanePriority。 var newCallbackPriority = getHighestPriorityLane(nextLanes); // Check if there's an existing task. We may be able to reuse it. var existingCallbackPriority = root.callbackPriority; // 比较新旧任务优先级,判断是否有必要发起一次新调度 if (existingCallbackPriority === newCallbackPriority && !( ReactCurrentActQueue$1.current !== null && existingCallbackNode !== fakeActCallbackNode)) { { ... } return; }

// 如果存在旧任务,那么看一下能否复用 if (existingCallbackNode != null) { cancelCallback$1(existingCallbackNode); }

// 调度一个新任务 var newCallbackNode; // 若新任务的优先级为同步优先级,则同步调度,传统的同步渲染和过期任务会走这里 if (newCallbackPriority === SyncLane) { if (root.tag === LegacyRoot) { if ( ReactCurrentActQueue$1.isBatchingLegacy !== null) { ReactCurrentActQueue$1.didScheduleLegacyUpdate = true; } scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root)); } else { scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); } { if ( ReactCurrentActQueue$1.current !== null) { ReactCurrentActQueue$1.current.push(flushSyncCallbacks); } else { scheduleMicrotask(function () { if (executionContext === NoContext) { flushSyncCallbacks(); } }); } } newCallbackNode = null; } else { var schedulerPriorityLevel; // 获取调度优先级 switch (lanesToEventPriority(nextLanes)) { ... } newCallbackNode = scheduleCallback$1(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root)); } root.callbackPriority = newCallbackPriority; root.callbackNode = newCallbackNode; }