diff --git a/packages/react-reconciler/src/ReactFiberLane.new.js b/packages/react-reconciler/src/ReactFiberLane.new.js index 49a9530734443..d34b0982048ac 100644 --- a/packages/react-reconciler/src/ReactFiberLane.new.js +++ b/packages/react-reconciler/src/ReactFiberLane.new.js @@ -7,7 +7,7 @@ * @flow */ -import type {FiberRoot} from './ReactInternalTypes'; +import type {FiberRoot, ReactPriorityLevel} from './ReactInternalTypes'; // TODO: Ideally these types would be opaque but that doesn't work well with // our reconciler fork infra, since these leak into non-reconciler packages. @@ -42,6 +42,15 @@ import { enableSyncDefaultUpdates, } from 'shared/ReactFeatureFlags'; import {isDevToolsPresent} from './ReactFiberDevToolsHook.new'; +import invariant from 'shared/invariant'; + +import { + ImmediatePriority as ImmediateSchedulerPriority, + UserBlockingPriority as UserBlockingSchedulerPriority, + NormalPriority as NormalSchedulerPriority, + IdlePriority as IdleSchedulerPriority, + NoPriority as NoSchedulerPriority, +} from './Scheduler'; export const SyncLanePriority: LanePriority = 12; @@ -241,6 +250,37 @@ function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes { } } +export function lanePriorityToSchedulerPriority( + lanePriority: LanePriority, +): ReactPriorityLevel { + switch (lanePriority) { + case SyncLanePriority: + return ImmediateSchedulerPriority; + case InputContinuousHydrationLanePriority: + case InputContinuousLanePriority: + return UserBlockingSchedulerPriority; + case DefaultHydrationLanePriority: + case DefaultLanePriority: + case TransitionHydrationPriority: + case TransitionPriority: + case SelectiveHydrationLanePriority: + case RetryLanePriority: + return NormalSchedulerPriority; + case IdleHydrationLanePriority: + case IdleLanePriority: + case OffscreenLanePriority: + return IdleSchedulerPriority; + case NoLanePriority: + return NoSchedulerPriority; + default: + invariant( + false, + 'Invalid update priority: %s. This is a bug in React.', + lanePriority, + ); + } +} + export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { // Early bailout if there's no pending work left. const pendingLanes = root.pendingLanes; diff --git a/packages/react-reconciler/src/ReactFiberLane.old.js b/packages/react-reconciler/src/ReactFiberLane.old.js index 568a49931f74c..ce73f6e07e935 100644 --- a/packages/react-reconciler/src/ReactFiberLane.old.js +++ b/packages/react-reconciler/src/ReactFiberLane.old.js @@ -7,7 +7,7 @@ * @flow */ -import type {FiberRoot} from './ReactInternalTypes'; +import type {FiberRoot, ReactPriorityLevel} from './ReactInternalTypes'; // TODO: Ideally these types would be opaque but that doesn't work well with // our reconciler fork infra, since these leak into non-reconciler packages. @@ -42,6 +42,15 @@ import { enableSyncDefaultUpdates, } from 'shared/ReactFeatureFlags'; import {isDevToolsPresent} from './ReactFiberDevToolsHook.old'; +import invariant from 'shared/invariant'; + +import { + ImmediatePriority as ImmediateSchedulerPriority, + UserBlockingPriority as UserBlockingSchedulerPriority, + NormalPriority as NormalSchedulerPriority, + IdlePriority as IdleSchedulerPriority, + NoPriority as NoSchedulerPriority, +} from './Scheduler'; export const SyncLanePriority: LanePriority = 12; @@ -241,6 +250,37 @@ function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes { } } +export function lanePriorityToSchedulerPriority( + lanePriority: LanePriority, +): ReactPriorityLevel { + switch (lanePriority) { + case SyncLanePriority: + return ImmediateSchedulerPriority; + case InputContinuousHydrationLanePriority: + case InputContinuousLanePriority: + return UserBlockingSchedulerPriority; + case DefaultHydrationLanePriority: + case DefaultLanePriority: + case TransitionHydrationPriority: + case TransitionPriority: + case SelectiveHydrationLanePriority: + case RetryLanePriority: + return NormalSchedulerPriority; + case IdleHydrationLanePriority: + case IdleLanePriority: + case OffscreenLanePriority: + return IdleSchedulerPriority; + case NoLanePriority: + return NoSchedulerPriority; + default: + invariant( + false, + 'Invalid update priority: %s. This is a bug in React.', + lanePriority, + ); + } +} + export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { // Early bailout if there's no pending work left. const pendingLanes = root.pendingLanes; diff --git a/packages/react-reconciler/src/ReactFiberRoot.new.js b/packages/react-reconciler/src/ReactFiberRoot.new.js index 9201a35980753..570eb5f3d1922 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.new.js +++ b/packages/react-reconciler/src/ReactFiberRoot.new.js @@ -13,8 +13,8 @@ import type {RootTag} from './ReactRootTags'; import {noTimeout, supportsHydration} from './ReactFiberHostConfig'; import {createHostRootFiber} from './ReactFiber.new'; import { - NoLane, NoLanes, + NoLanePriority, NoTimestamp, TotalLanes, createLaneMap, @@ -43,7 +43,7 @@ function FiberRootNode(containerInfo, tag, hydrate) { this.pendingContext = null; this.hydrate = hydrate; this.callbackNode = null; - this.callbackPriority = NoLane; + this.callbackPriority = NoLanePriority; this.eventTimes = createLaneMap(NoLanes); this.expirationTimes = createLaneMap(NoTimestamp); diff --git a/packages/react-reconciler/src/ReactFiberRoot.old.js b/packages/react-reconciler/src/ReactFiberRoot.old.js index f2968b314ecae..29e341480ef71 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.old.js +++ b/packages/react-reconciler/src/ReactFiberRoot.old.js @@ -13,8 +13,8 @@ import type {RootTag} from './ReactRootTags'; import {noTimeout, supportsHydration} from './ReactFiberHostConfig'; import {createHostRootFiber} from './ReactFiber.old'; import { - NoLane, NoLanes, + NoLanePriority, NoTimestamp, TotalLanes, createLaneMap, @@ -43,7 +43,7 @@ function FiberRootNode(containerInfo, tag, hydrate) { this.pendingContext = null; this.hydrate = hydrate; this.callbackNode = null; - this.callbackPriority = NoLane; + this.callbackPriority = NoLanePriority; this.eventTimes = createLaneMap(NoLanes); this.expirationTimes = createLaneMap(NoTimestamp); diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index f5e2c7b704048..540ead76f0793 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -44,9 +44,7 @@ import { requestPaint, now, ImmediatePriority as ImmediateSchedulerPriority, - UserBlockingPriority as UserBlockingSchedulerPriority, NormalPriority as NormalSchedulerPriority, - IdlePriority as IdleSchedulerPriority, } from './Scheduler'; import { flushSyncCallbacks, @@ -137,6 +135,8 @@ import { MountLayoutDev, } from './ReactFiberFlags'; import { + NoLanePriority, + SyncLanePriority, NoLanes, NoLane, SyncLane, @@ -153,6 +153,7 @@ import { includesOnlyTransitions, shouldTimeSlice, getNextLanes, + returnNextLanesPriority, markStarvedLanesAsExpired, getLanesToRetrySynchronouslyOnError, getMostRecentEventTime, @@ -161,15 +162,13 @@ import { markRootPinged, markRootExpired, markRootFinished, - getHighestPriorityLane, addFiberToLanesMap, movePendingFibersToMemoized, + lanePriorityToSchedulerPriority, } from './ReactFiberLane.new'; import { DiscreteEventPriority, - ContinuousEventPriority, DefaultEventPriority, - IdleEventPriority, getCurrentUpdatePriority, setCurrentUpdatePriority, lowerEventPriority, @@ -655,6 +654,8 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes, ); + // This returns the priority level computed during the `getNextLanes` call. + const newCallbackPriority = returnNextLanesPriority(); if (nextLanes === NoLanes) { // Special case: There's nothing to work on. @@ -662,13 +663,10 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { cancelCallback(existingCallbackNode); } root.callbackNode = null; - root.callbackPriority = NoLane; + root.callbackPriority = NoLanePriority; return; } - // We use the highest priority lane to represent the priority of the callback. - const newCallbackPriority = getHighestPriorityLane(nextLanes); - // Check if there's an existing task. We may be able to reuse it. const existingCallbackPriority = root.callbackPriority; if (existingCallbackPriority === newCallbackPriority) { @@ -678,7 +676,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // TODO: Temporary until we confirm this warning is not fired. if ( existingCallbackNode == null && - existingCallbackPriority !== SyncLane + existingCallbackPriority !== SyncLanePriority ) { console.error( 'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.', @@ -696,7 +694,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // Schedule a new callback. let newCallbackNode; - if (newCallbackPriority === SyncLane) { + if (newCallbackPriority === SyncLanePriority) { // Special case: Sync React callbacks are scheduled on a special // internal queue if (root.tag === LegacyRoot) { @@ -713,24 +711,9 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { } newCallbackNode = null; } else { - let schedulerPriorityLevel; - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediateSchedulerPriority; - break; - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingSchedulerPriority; - break; - case DefaultEventPriority: - schedulerPriorityLevel = NormalSchedulerPriority; - break; - case IdleEventPriority: - schedulerPriorityLevel = IdleSchedulerPriority; - break; - default: - schedulerPriorityLevel = NormalSchedulerPriority; - break; - } + const schedulerPriorityLevel = lanePriorityToSchedulerPriority( + newCallbackPriority, + ); newCallbackNode = scheduleCallback( schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root), @@ -1816,7 +1799,7 @@ function commitRootImpl(root, renderPriorityLevel) { // commitRoot never returns a continuation; it always finishes synchronously. // So we can clear these now to allow a new callback to be scheduled. root.callbackNode = null; - root.callbackPriority = NoLane; + root.callbackPriority = NoLanePriority; // Update the first and last pending times on this root. The new first // pending time is whatever is left on the root fiber. diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js index c4c23807138dd..a00f3d263b970 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js @@ -44,9 +44,7 @@ import { requestPaint, now, ImmediatePriority as ImmediateSchedulerPriority, - UserBlockingPriority as UserBlockingSchedulerPriority, NormalPriority as NormalSchedulerPriority, - IdlePriority as IdleSchedulerPriority, } from './Scheduler'; import { flushSyncCallbacks, @@ -137,6 +135,8 @@ import { MountLayoutDev, } from './ReactFiberFlags'; import { + NoLanePriority, + SyncLanePriority, NoLanes, NoLane, SyncLane, @@ -153,6 +153,7 @@ import { includesOnlyTransitions, shouldTimeSlice, getNextLanes, + returnNextLanesPriority, markStarvedLanesAsExpired, getLanesToRetrySynchronouslyOnError, getMostRecentEventTime, @@ -161,15 +162,13 @@ import { markRootPinged, markRootExpired, markRootFinished, - getHighestPriorityLane, addFiberToLanesMap, movePendingFibersToMemoized, + lanePriorityToSchedulerPriority, } from './ReactFiberLane.old'; import { DiscreteEventPriority, - ContinuousEventPriority, DefaultEventPriority, - IdleEventPriority, getCurrentUpdatePriority, setCurrentUpdatePriority, lowerEventPriority, @@ -655,6 +654,8 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes, ); + // This returns the priority level computed during the `getNextLanes` call. + const newCallbackPriority = returnNextLanesPriority(); if (nextLanes === NoLanes) { // Special case: There's nothing to work on. @@ -662,13 +663,10 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { cancelCallback(existingCallbackNode); } root.callbackNode = null; - root.callbackPriority = NoLane; + root.callbackPriority = NoLanePriority; return; } - // We use the highest priority lane to represent the priority of the callback. - const newCallbackPriority = getHighestPriorityLane(nextLanes); - // Check if there's an existing task. We may be able to reuse it. const existingCallbackPriority = root.callbackPriority; if (existingCallbackPriority === newCallbackPriority) { @@ -678,7 +676,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // TODO: Temporary until we confirm this warning is not fired. if ( existingCallbackNode == null && - existingCallbackPriority !== SyncLane + existingCallbackPriority !== SyncLanePriority ) { console.error( 'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.', @@ -696,7 +694,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // Schedule a new callback. let newCallbackNode; - if (newCallbackPriority === SyncLane) { + if (newCallbackPriority === SyncLanePriority) { // Special case: Sync React callbacks are scheduled on a special // internal queue if (root.tag === LegacyRoot) { @@ -713,24 +711,9 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { } newCallbackNode = null; } else { - let schedulerPriorityLevel; - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediateSchedulerPriority; - break; - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingSchedulerPriority; - break; - case DefaultEventPriority: - schedulerPriorityLevel = NormalSchedulerPriority; - break; - case IdleEventPriority: - schedulerPriorityLevel = IdleSchedulerPriority; - break; - default: - schedulerPriorityLevel = NormalSchedulerPriority; - break; - } + const schedulerPriorityLevel = lanePriorityToSchedulerPriority( + newCallbackPriority, + ); newCallbackNode = scheduleCallback( schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root), @@ -1816,7 +1799,7 @@ function commitRootImpl(root, renderPriorityLevel) { // commitRoot never returns a continuation; it always finishes synchronously. // So we can clear these now to allow a new callback to be scheduled. root.callbackNode = null; - root.callbackPriority = NoLane; + root.callbackPriority = NoLanePriority; // Update the first and last pending times on this root. The new first // pending time is whatever is left on the root fiber. diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index 08f5cbc2d0e9a..7596d0ba005d4 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -20,7 +20,7 @@ import type {SuspenseInstance} from './ReactFiberHostConfig'; import type {WorkTag} from './ReactWorkTags'; import type {TypeOfMode} from './ReactTypeOfMode'; import type {Flags} from './ReactFiberFlags'; -import type {Lane, Lanes, LaneMap} from './ReactFiberLane.old'; +import type {Lane, LanePriority, Lanes, LaneMap} from './ReactFiberLane.old'; import type {RootTag} from './ReactRootTags'; import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig'; import type {Wakeable} from 'shared/ReactTypes'; @@ -221,7 +221,7 @@ type BaseFiberRootProperties = {| // Node returned by Scheduler.scheduleCallback. Represents the next rendering // task that the root will work on. callbackNode: *, - callbackPriority: Lane, + callbackPriority: LanePriority, eventTimes: LaneMap, expirationTimes: LaneMap,