From 96c7ce3e1a7bb4f17a9d407e3930842355d79fdf Mon Sep 17 00:00:00 2001 From: Tianyu Yao Date: Mon, 10 Oct 2022 17:25:42 -0700 Subject: [PATCH] Separate EventPriority from Lane --- .../src/ReactEventPriorities.js | 2 +- .../src/ReactEventPriorities.new.js | 21 ++++++++-- .../src/ReactEventPriorities.old.js | 21 ++++++++-- .../src/ReactFiberRoot.new.js | 4 +- .../src/ReactFiberRoot.old.js | 4 +- .../src/ReactFiberWorkLoop.new.js | 42 ++++++++++++------- .../src/ReactFiberWorkLoop.old.js | 42 ++++++++++++------- .../src/ReactInternalTypes.js | 5 ++- 8 files changed, 98 insertions(+), 43 deletions(-) diff --git a/packages/react-reconciler/src/ReactEventPriorities.js b/packages/react-reconciler/src/ReactEventPriorities.js index 1aff2a4c91f80..dba1677c187ab 100644 --- a/packages/react-reconciler/src/ReactEventPriorities.js +++ b/packages/react-reconciler/src/ReactEventPriorities.js @@ -31,7 +31,7 @@ import { isHigherEventPriority as isHigherEventPriority_new, } from './ReactEventPriorities.new'; -export opaque type EventPriority = number; +export type EventPriority = number; export const DiscreteEventPriority: EventPriority = enableNewReconciler ? (DiscreteEventPriority_new: any) diff --git a/packages/react-reconciler/src/ReactEventPriorities.new.js b/packages/react-reconciler/src/ReactEventPriorities.new.js index f9cc1e3ee9338..621477636ebd2 100644 --- a/packages/react-reconciler/src/ReactEventPriorities.new.js +++ b/packages/react-reconciler/src/ReactEventPriorities.new.js @@ -19,14 +19,17 @@ import { includesNonIdleWork, } from './ReactFiberLane.new'; -export opaque type EventPriority = Lane; +// TODO: Ideally this would be opaque but that doesn't work well with +// our reconciler fork infra, since these leak into non-reconciler packages. +export type EventPriority = number; +export const NoEventPriority: EventPriority = NoLane; export const DiscreteEventPriority: EventPriority = SyncLane; -export const ContinuousEventPriority: EventPriority = InputContinuousLane; -export const DefaultEventPriority: EventPriority = DefaultLane; +export const ContinuousEventPriority: EventPriority = SyncLane | (2 << 1); +export const DefaultEventPriority: EventPriority = SyncLane | (1 << 1); export const IdleEventPriority: EventPriority = IdleLane; -let currentUpdatePriority: EventPriority = NoLane; +let currentUpdatePriority: EventPriority = NoEventPriority; export function getCurrentUpdatePriority(): EventPriority { return currentUpdatePriority; @@ -80,3 +83,13 @@ export function lanesToEventPriority(lanes: Lanes): EventPriority { } return IdleEventPriority; } + +export function laneToEventPriority(lane: Lane): EventPriority { + if (lane === DefaultLane) { + return DefaultEventPriority; + } + if (lane === InputContinuousLane) { + return ContinuousEventPriority; + } + return (lane: any); +} diff --git a/packages/react-reconciler/src/ReactEventPriorities.old.js b/packages/react-reconciler/src/ReactEventPriorities.old.js index 9223b2e745306..f0b006091af99 100644 --- a/packages/react-reconciler/src/ReactEventPriorities.old.js +++ b/packages/react-reconciler/src/ReactEventPriorities.old.js @@ -19,14 +19,17 @@ import { includesNonIdleWork, } from './ReactFiberLane.old'; -export opaque type EventPriority = Lane; +// TODO: Ideally this would be opaque but that doesn't work well with +// our reconciler fork infra, since these leak into non-reconciler packages. +export type EventPriority = number; +export const NoEventPriority: EventPriority = NoLane; export const DiscreteEventPriority: EventPriority = SyncLane; -export const ContinuousEventPriority: EventPriority = InputContinuousLane; -export const DefaultEventPriority: EventPriority = DefaultLane; +export const ContinuousEventPriority: EventPriority = SyncLane | (2 << 1); +export const DefaultEventPriority: EventPriority = SyncLane | (1 << 1); export const IdleEventPriority: EventPriority = IdleLane; -let currentUpdatePriority: EventPriority = NoLane; +let currentUpdatePriority: EventPriority = NoEventPriority; export function getCurrentUpdatePriority(): EventPriority { return currentUpdatePriority; @@ -80,3 +83,13 @@ export function lanesToEventPriority(lanes: Lanes): EventPriority { } return IdleEventPriority; } + +export function laneToEventPriority(lane: Lane): EventPriority { + if (lane === DefaultLane) { + return DefaultEventPriority; + } + if (lane === InputContinuousLane) { + return ContinuousEventPriority; + } + return (lane: any); +} diff --git a/packages/react-reconciler/src/ReactFiberRoot.new.js b/packages/react-reconciler/src/ReactFiberRoot.new.js index c613fa5dd31bf..566cefa1289c5 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.new.js +++ b/packages/react-reconciler/src/ReactFiberRoot.new.js @@ -20,12 +20,12 @@ import type {Container} from './ReactFiberHostConfig'; import {noTimeout, supportsHydration} from './ReactFiberHostConfig'; import {createHostRootFiber} from './ReactFiber.new'; import { - NoLane, NoLanes, NoTimestamp, TotalLanes, createLaneMap, } from './ReactFiberLane.new'; +import {NoEventPriority} from './ReactEventPriorities.new'; import { enableSuspenseCallback, enableCache, @@ -61,7 +61,7 @@ function FiberRootNode( this.context = null; this.pendingContext = null; this.callbackNode = null; - this.callbackPriority = NoLane; + this.callbackPriority = NoEventPriority; 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 f19ec89ff8f9f..8f5a22442af55 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.old.js +++ b/packages/react-reconciler/src/ReactFiberRoot.old.js @@ -20,12 +20,12 @@ import type {Container} from './ReactFiberHostConfig'; import {noTimeout, supportsHydration} from './ReactFiberHostConfig'; import {createHostRootFiber} from './ReactFiber.old'; import { - NoLane, NoLanes, NoTimestamp, TotalLanes, createLaneMap, } from './ReactFiberLane.old'; +import {NoEventPriority} from './ReactEventPriorities.old'; import { enableSuspenseCallback, enableCache, @@ -61,7 +61,7 @@ function FiberRootNode( this.context = null; this.pendingContext = null; this.callbackNode = null; - this.callbackPriority = NoLane; + this.callbackPriority = NoEventPriority; 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 a2fa1f6ae9c3f..c7ab6a960d9ba 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -166,16 +166,20 @@ import { movePendingFibersToMemoized, addTransitionToLanesMap, getTransitionsForLanes, + InputContinuousLane, + DefaultLane, } from './ReactFiberLane.new'; import { DiscreteEventPriority, ContinuousEventPriority, DefaultEventPriority, + NoEventPriority, IdleEventPriority, getCurrentUpdatePriority, setCurrentUpdatePriority, lowerEventPriority, lanesToEventPriority, + laneToEventPriority, } from './ReactEventPriorities.new'; import {requestCurrentTransition, NoTransition} from './ReactFiberTransition'; import {beginWork as originalBeginWork} from './ReactFiberBeginWork.new'; @@ -663,22 +667,30 @@ export function requestUpdateLane(fiber: Fiber): Lane { // Updates originating inside certain React methods, like flushSync, have // their priority set by tracking it with a context variable. // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. // TODO: Move this type conversion to the event priority module. - const updateLane: Lane = (getCurrentUpdatePriority(): any); - if (updateLane !== NoLane) { - return updateLane; + const updatePriority = getCurrentUpdatePriority(); + if (updatePriority !== NoEventPriority) { + if (updatePriority === DefaultEventPriority) { + return DefaultLane; + } + if (updatePriority === ContinuousEventPriority) { + return InputContinuousLane; + } + return (updatePriority: any); } // This update originated outside React. Ask the host environment for an // appropriate priority, based on the type of event. // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. // TODO: Move this type conversion to the event priority module. - const eventLane: Lane = (getCurrentEventPriority(): any); - return eventLane; + const eventPriority = getCurrentEventPriority(); + if (eventPriority === DefaultEventPriority) { + return DefaultLane; + } + if (eventPriority === ContinuousEventPriority) { + return InputContinuousLane; + } + return (eventPriority: any); } function requestRetryLane(fiber: Fiber) { @@ -887,12 +899,14 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { cancelCallback(existingCallbackNode); } root.callbackNode = null; - root.callbackPriority = NoLane; + root.callbackPriority = NoEventPriority; return; } // We use the highest priority lane to represent the priority of the callback. - const newCallbackPriority = getHighestPriorityLane(nextLanes); + const newCallbackPriority = laneToEventPriority( + getHighestPriorityLane(nextLanes), + ); // Check if there's an existing task. We may be able to reuse it. const existingCallbackPriority = root.callbackPriority; @@ -913,7 +927,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // TODO: Temporary until we confirm this warning is not fired. if ( existingCallbackNode == null && - existingCallbackPriority !== SyncLane + existingCallbackPriority !== DiscreteEventPriority ) { console.error( 'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.', @@ -931,7 +945,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // Schedule a new callback. let newCallbackNode; - if (newCallbackPriority === SyncLane) { + if (newCallbackPriority === DiscreteEventPriority) { // Special case: Sync React callbacks are scheduled on a special // internal queue if (root.tag === LegacyRoot) { @@ -2547,7 +2561,7 @@ function commitRootImpl( // 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 = NoEventPriority; // Check which lanes no longer have any work scheduled on them, and mark // those as finished. diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js index f08ae039c5b14..c5e86c70484f1 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js @@ -166,16 +166,20 @@ import { movePendingFibersToMemoized, addTransitionToLanesMap, getTransitionsForLanes, + InputContinuousLane, + DefaultLane, } from './ReactFiberLane.old'; import { DiscreteEventPriority, ContinuousEventPriority, DefaultEventPriority, + NoEventPriority, IdleEventPriority, getCurrentUpdatePriority, setCurrentUpdatePriority, lowerEventPriority, lanesToEventPriority, + laneToEventPriority, } from './ReactEventPriorities.old'; import {requestCurrentTransition, NoTransition} from './ReactFiberTransition'; import {beginWork as originalBeginWork} from './ReactFiberBeginWork.old'; @@ -663,22 +667,30 @@ export function requestUpdateLane(fiber: Fiber): Lane { // Updates originating inside certain React methods, like flushSync, have // their priority set by tracking it with a context variable. // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. // TODO: Move this type conversion to the event priority module. - const updateLane: Lane = (getCurrentUpdatePriority(): any); - if (updateLane !== NoLane) { - return updateLane; + const updatePriority = getCurrentUpdatePriority(); + if (updatePriority !== NoEventPriority) { + if (updatePriority === DefaultEventPriority) { + return DefaultLane; + } + if (updatePriority === ContinuousEventPriority) { + return InputContinuousLane; + } + return (updatePriority: any); } // This update originated outside React. Ask the host environment for an // appropriate priority, based on the type of event. // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. // TODO: Move this type conversion to the event priority module. - const eventLane: Lane = (getCurrentEventPriority(): any); - return eventLane; + const eventPriority = getCurrentEventPriority(); + if (eventPriority === DefaultEventPriority) { + return DefaultLane; + } + if (eventPriority === ContinuousEventPriority) { + return InputContinuousLane; + } + return (eventPriority: any); } function requestRetryLane(fiber: Fiber) { @@ -887,12 +899,14 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { cancelCallback(existingCallbackNode); } root.callbackNode = null; - root.callbackPriority = NoLane; + root.callbackPriority = NoEventPriority; return; } // We use the highest priority lane to represent the priority of the callback. - const newCallbackPriority = getHighestPriorityLane(nextLanes); + const newCallbackPriority = laneToEventPriority( + getHighestPriorityLane(nextLanes), + ); // Check if there's an existing task. We may be able to reuse it. const existingCallbackPriority = root.callbackPriority; @@ -913,7 +927,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // TODO: Temporary until we confirm this warning is not fired. if ( existingCallbackNode == null && - existingCallbackPriority !== SyncLane + existingCallbackPriority !== DiscreteEventPriority ) { console.error( 'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.', @@ -931,7 +945,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // Schedule a new callback. let newCallbackNode; - if (newCallbackPriority === SyncLane) { + if (newCallbackPriority === DiscreteEventPriority) { // Special case: Sync React callbacks are scheduled on a special // internal queue if (root.tag === LegacyRoot) { @@ -2547,7 +2561,7 @@ function commitRootImpl( // 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 = NoEventPriority; // Check which lanes no longer have any work scheduled on them, and mark // those as finished. diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index a5f28fd5d2450..374a1f77e13ba 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -22,7 +22,8 @@ import type { 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 {Lanes, LaneMap} from './ReactFiberLane.old'; +import type {EventPriority} from './ReactEventPriorities'; import type {RootTag} from './ReactRootTags'; import type { Container, @@ -239,7 +240,7 @@ type BaseFiberRootProperties = { // Node returned by Scheduler.scheduleCallback. Represents the next rendering // task that the root will work on. callbackNode: any, - callbackPriority: Lane, + callbackPriority: EventPriority, eventTimes: LaneMap, expirationTimes: LaneMap, hiddenUpdates: LaneMap | null>,