diff --git a/packages/react-art/src/ReactFiberConfigART.js b/packages/react-art/src/ReactFiberConfigART.js index d0ae53019cac6..0900c50f7e94e 100644 --- a/packages/react-art/src/ReactFiberConfigART.js +++ b/packages/react-art/src/ReactFiberConfigART.js @@ -5,12 +5,17 @@ * LICENSE file in the root directory of this source tree. */ +import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities'; + import Transform from 'art/core/transform'; import Mode from 'art/modes/current'; import {TYPES, EVENT_TYPES, childrenAsString} from './ReactARTInternals'; -import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities'; +import { + DefaultEventPriority, + NoEventPriority, +} from 'react-reconciler/src/ReactEventPriorities'; const pooledTransform = new Transform(); @@ -336,8 +341,18 @@ export function shouldSetTextContent(type, props) { ); } -export function getCurrentEventPriority() { - return DefaultEventPriority; +let currentUpdatePriority: EventPriority = NoEventPriority; + +export function setCurrentUpdatePriority(newPriority: EventPriority): void { + currentUpdatePriority = newPriority; +} + +export function getCurrentUpdatePriority(): EventPriority { + return currentUpdatePriority; +} + +export function resolveUpdatePriority(): EventPriority { + return currentUpdatePriority || DefaultEventPriority; } export function shouldAttemptEagerTransition() { diff --git a/packages/react-dom-bindings/src/client/ReactDOMUpdatePriority.js b/packages/react-dom-bindings/src/client/ReactDOMUpdatePriority.js new file mode 100644 index 0000000000000..a0c4273bec604 --- /dev/null +++ b/packages/react-dom-bindings/src/client/ReactDOMUpdatePriority.js @@ -0,0 +1,55 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities'; + +import {getEventPriority} from '../events/ReactDOMEventListener'; +import { + NoEventPriority, + DefaultEventPriority, +} from 'react-reconciler/src/ReactEventPriorities'; + +import ReactDOMSharedInternals from 'shared/ReactDOMSharedInternals'; + +export function setCurrentUpdatePriority( + newPriority: EventPriority, + // Closure will consistently not inline this function when it has arity 1 + // however when it has arity 2 even if the second arg is omitted at every + // callsite it seems to inline it even when the internal length of the function + // is much longer. I hope this is consistent enough to rely on across builds + IntentionallyUnusedArgument?: empty, +): void { + ReactDOMSharedInternals.up = newPriority; +} + +export function getCurrentUpdatePriority(): EventPriority { + return ReactDOMSharedInternals.up; +} + +export function resolveUpdatePriority(): EventPriority { + const updatePriority = ReactDOMSharedInternals.up; + if (updatePriority !== NoEventPriority) { + return updatePriority; + } + const currentEvent = window.event; + if (currentEvent === undefined) { + return DefaultEventPriority; + } + return getEventPriority(currentEvent.type); +} + +export function runWithPriority(priority: EventPriority, fn: () => T): T { + const previousPriority = getCurrentUpdatePriority(); + try { + setCurrentUpdatePriority(priority); + return fn(); + } finally { + setCurrentUpdatePriority(previousPriority); + } +} diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 9b9f41a92d374..504172309f9c5 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -7,7 +7,6 @@ * @flow */ -import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities'; import type {DOMEventName} from '../events/DOMEventNames'; import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes'; import type { @@ -29,11 +28,15 @@ import type { import {NotPending} from 'react-dom-bindings/src/shared/ReactDOMFormActions'; import {getCurrentRootHostContainer} from 'react-reconciler/src/ReactFiberHostContext'; -import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities'; import hasOwnProperty from 'shared/hasOwnProperty'; import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion'; +export { + setCurrentUpdatePriority, + getCurrentUpdatePriority, + resolveUpdatePriority, +} from './ReactDOMUpdatePriority'; import { precacheFiberNode, updateFiberProps, @@ -69,7 +72,6 @@ import { import { isEnabled as ReactBrowserEventEmitterIsEnabled, setEnabled as ReactBrowserEventEmitterSetEnabled, - getEventPriority, } from '../events/ReactDOMEventListener'; import {SVG_NAMESPACE, MATH_NAMESPACE} from './DOMNamespaces'; import { @@ -572,14 +574,6 @@ export function createTextInstance( return textNode; } -export function getCurrentEventPriority(): EventPriority { - const currentEvent = window.event; - if (currentEvent === undefined) { - return DefaultEventPriority; - } - return getEventPriority(currentEvent.type); -} - let currentPopstateTransitionEvent: Event | null = null; export function shouldAttemptEagerTransition(): boolean { const event = window.event; diff --git a/packages/react-dom-bindings/src/events/ReactDOMEventListener.js b/packages/react-dom-bindings/src/events/ReactDOMEventListener.js index 237cde231176b..525f7bd358c90 100644 --- a/packages/react-dom-bindings/src/events/ReactDOMEventListener.js +++ b/packages/react-dom-bindings/src/events/ReactDOMEventListener.js @@ -34,6 +34,10 @@ import { } from '../client/ReactDOMComponentTree'; import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem'; +import { + getCurrentUpdatePriority, + setCurrentUpdatePriority, +} from '../client/ReactDOMUpdatePriority'; import { getCurrentPriorityLevel as getCurrentSchedulerPriorityLevel, @@ -48,8 +52,6 @@ import { ContinuousEventPriority, DefaultEventPriority, IdleEventPriority, - getCurrentUpdatePriority, - setCurrentUpdatePriority, } from 'react-reconciler/src/ReactEventPriorities'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import {isRootDehydrated} from 'react-reconciler/src/ReactFiberShellHydration'; @@ -115,9 +117,9 @@ function dispatchDiscreteEvent( container: EventTarget, nativeEvent: AnyNativeEvent, ) { - const previousPriority = getCurrentUpdatePriority(); const prevTransition = ReactCurrentBatchConfig.transition; ReactCurrentBatchConfig.transition = null; + const previousPriority = getCurrentUpdatePriority(); try { setCurrentUpdatePriority(DiscreteEventPriority); dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); @@ -133,9 +135,9 @@ function dispatchContinuousEvent( container: EventTarget, nativeEvent: AnyNativeEvent, ) { - const previousPriority = getCurrentUpdatePriority(); const prevTransition = ReactCurrentBatchConfig.transition; ReactCurrentBatchConfig.transition = null; + const previousPriority = getCurrentUpdatePriority(); try { setCurrentUpdatePriority(ContinuousEventPriority); dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); diff --git a/packages/react-dom-bindings/src/events/ReactDOMEventReplaying.js b/packages/react-dom-bindings/src/events/ReactDOMEventReplaying.js index 5a3e6919cb364..fc5e59eb839e5 100644 --- a/packages/react-dom-bindings/src/events/ReactDOMEventReplaying.js +++ b/packages/react-dom-bindings/src/events/ReactDOMEventReplaying.js @@ -37,15 +37,15 @@ import {HostRoot, SuspenseComponent} from 'react-reconciler/src/ReactWorkTags'; import {isHigherEventPriority} from 'react-reconciler/src/ReactEventPriorities'; import {isRootDehydrated} from 'react-reconciler/src/ReactFiberShellHydration'; import {dispatchReplayedFormAction} from './plugins/FormActionEventPlugin'; +import { + getCurrentUpdatePriority, + runWithPriority as attemptHydrationAtPriority, +} from '../client/ReactDOMUpdatePriority'; import { attemptContinuousHydration, attemptHydrationAtCurrentPriority, } from 'react-reconciler/src/ReactFiberReconciler'; -import { - runWithPriority as attemptHydrationAtPriority, - getCurrentUpdatePriority, -} from 'react-reconciler/src/ReactEventPriorities'; // TODO: Upgrade this definition once we're on a newer version of Flow that // has this definition built-in. diff --git a/packages/react-dom/src/ReactDOMSharedInternals.js b/packages/react-dom/src/ReactDOMSharedInternals.js index 7bd080ce48240..f2dd23c26660f 100644 --- a/packages/react-dom/src/ReactDOMSharedInternals.js +++ b/packages/react-dom/src/ReactDOMSharedInternals.js @@ -7,8 +7,11 @@ * @flow */ +import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities'; import type {HostDispatcher} from './shared/ReactDOMTypes'; +import {NoEventPriority} from 'react-reconciler/src/ReactEventPriorities'; + type InternalsType = { usingClientEntryPoint: boolean, Events: [any, any, any, any, any, any], @@ -20,6 +23,7 @@ type InternalsType = { | (( componentOrElement: React$Component, ) => null | Element | Text), + up /* currentUpdatePriority */: EventPriority, }; function noop() {} @@ -34,13 +38,14 @@ const DefaultDispatcher: HostDispatcher = { preinitModuleScript: noop, }; -const Internals: InternalsType = ({ +const Internals: InternalsType = { usingClientEntryPoint: false, - Events: null, + Events: (null: any), ReactDOMCurrentDispatcher: { current: DefaultDispatcher, }, findDOMNode: null, -}: any); + up /* currentUpdatePriority */: NoEventPriority, +}; export default Internals; diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js index e0cbe30a079f3..04b59d618aeb1 100644 --- a/packages/react-dom/src/client/ReactDOM.js +++ b/packages/react-dom/src/client/ReactDOM.js @@ -20,6 +20,7 @@ import { isValidContainer, } from './ReactDOMRoot'; import {createEventHandle} from 'react-dom-bindings/src/client/ReactDOMEventHandle'; +import {runWithPriority} from 'react-dom-bindings/src/client/ReactDOMUpdatePriority'; import { flushSync as flushSyncWithoutWarningIfAlreadyRendering, @@ -27,7 +28,6 @@ import { injectIntoDevTools, findHostInstance, } from 'react-reconciler/src/ReactFiberReconciler'; -import {runWithPriority} from 'react-reconciler/src/ReactEventPriorities'; import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal'; import {canUseDOM} from 'shared/ExecutionEnvironment'; import ReactVersion from 'shared/ReactVersion'; diff --git a/packages/react-native-renderer/src/ReactFiberConfigFabric.js b/packages/react-native-renderer/src/ReactFiberConfigFabric.js index e0f46a07822c3..0a4f30c901531 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigFabric.js +++ b/packages/react-native-renderer/src/ReactFiberConfigFabric.js @@ -15,6 +15,7 @@ import type { import {create, diff} from './ReactNativeAttributePayload'; import {dispatchEvent} from './ReactFabricEventEmitter'; import { + NoEventPriority, DefaultEventPriority, DiscreteEventPriority, type EventPriority, @@ -311,7 +312,20 @@ export function shouldSetTextContent(type: string, props: Props): boolean { return false; } -export function getCurrentEventPriority(): EventPriority { +let currentUpdatePriority: EventPriority = NoEventPriority; +export function setCurrentUpdatePriority(newPriority: EventPriority): void { + currentUpdatePriority = newPriority; +} + +export function getCurrentUpdatePriority(): EventPriority { + return currentUpdatePriority; +} + +export function resolveUpdatePriority(): EventPriority { + if (currentUpdatePriority !== NoEventPriority) { + return currentUpdatePriority; + } + const currentEventPriority = fabricGetCurrentEventPriority ? fabricGetCurrentEventPriority() : null; diff --git a/packages/react-native-renderer/src/ReactFiberConfigNative.js b/packages/react-native-renderer/src/ReactFiberConfigNative.js index b61c8ef292a40..c24c3a0c95f4f 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigNative.js +++ b/packages/react-native-renderer/src/ReactFiberConfigNative.js @@ -26,6 +26,7 @@ import ReactNativeFiberHostComponent from './ReactNativeFiberHostComponent'; import { DefaultEventPriority, + NoEventPriority, type EventPriority, } from 'react-reconciler/src/ReactEventPriorities'; import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; @@ -253,7 +254,19 @@ export function shouldSetTextContent(type: string, props: Props): boolean { return false; } -export function getCurrentEventPriority(): EventPriority { +let currentUpdatePriority: EventPriority = NoEventPriority; +export function setCurrentUpdatePriority(newPriority: EventPriority): void { + currentUpdatePriority = newPriority; +} + +export function getCurrentUpdatePriority(): EventPriority { + return currentUpdatePriority; +} + +export function resolveUpdatePriority(): EventPriority { + if (currentUpdatePriority !== NoEventPriority) { + return currentUpdatePriority; + } return DefaultEventPriority; } diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 03937ee02cfcb..382016e3161ee 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -21,12 +21,14 @@ import type { import type {UpdateQueue} from 'react-reconciler/src/ReactFiberClassUpdateQueue'; import type {ReactNodeList} from 'shared/ReactTypes'; import type {RootTag} from 'react-reconciler/src/ReactRootTags'; +import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities'; import * as Scheduler from 'scheduler/unstable_mock'; import {REACT_FRAGMENT_TYPE, REACT_ELEMENT_TYPE} from 'shared/ReactSymbols'; import isArray from 'shared/isArray'; import {checkPropStringCoercion} from 'shared/CheckStringCoercion'; import { + NoEventPriority, DefaultEventPriority, IdleEventPriority, ConcurrentRoot, @@ -508,7 +510,13 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { resetAfterCommit(): void {}, - getCurrentEventPriority() { + setCurrentUpdatePriority, + getCurrentUpdatePriority, + + resolveUpdatePriority() { + if (currentUpdatePriority !== NoEventPriority) { + return currentUpdatePriority; + } return currentEventPriority; }, @@ -782,6 +790,15 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { const roots = new Map(); const DEFAULT_ROOT_ID = ''; + let currentUpdatePriority = NoEventPriority; + function setCurrentUpdatePriority(newPriority: EventPriority): void { + currentUpdatePriority = newPriority; + } + + function getCurrentUpdatePriority(): EventPriority { + return currentUpdatePriority; + } + let currentEventPriority = DefaultEventPriority; function createJSXElementForTestComparison(type, props) { @@ -1211,7 +1228,18 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { return Scheduler.unstable_flushExpired(); }, - unstable_runWithPriority: NoopRenderer.runWithPriority, + unstable_runWithPriority: function runWithPriority( + priority: EventPriority, + fn: () => T, + ): T { + const previousPriority = getCurrentUpdatePriority(); + try { + setCurrentUpdatePriority(priority); + return fn(); + } finally { + setCurrentUpdatePriority(previousPriority); + } + }, batchedUpdates: NoopRenderer.batchedUpdates, diff --git a/packages/react-reconciler/src/ReactEventPriorities.js b/packages/react-reconciler/src/ReactEventPriorities.js index 6ae2f85f4b6ed..e28223e9d89b1 100644 --- a/packages/react-reconciler/src/ReactEventPriorities.js +++ b/packages/react-reconciler/src/ReactEventPriorities.js @@ -21,31 +21,12 @@ import { export opaque type EventPriority = Lane; +export const NoEventPriority: EventPriority = NoLane; export const DiscreteEventPriority: EventPriority = SyncLane; export const ContinuousEventPriority: EventPriority = InputContinuousLane; export const DefaultEventPriority: EventPriority = DefaultLane; export const IdleEventPriority: EventPriority = IdleLane; -let currentUpdatePriority: EventPriority = NoLane; - -export function getCurrentUpdatePriority(): EventPriority { - return currentUpdatePriority; -} - -export function setCurrentUpdatePriority(newPriority: EventPriority) { - currentUpdatePriority = newPriority; -} - -export function runWithPriority(priority: EventPriority, fn: () => T): T { - const previousPriority = currentUpdatePriority; - try { - currentUpdatePriority = priority; - return fn(); - } finally { - currentUpdatePriority = previousPriority; - } -} - export function higherEventPriority( a: EventPriority, b: EventPriority, @@ -67,6 +48,10 @@ export function isHigherEventPriority( return a !== 0 && a < b; } +export function eventPriorityToLane(updatePriority: EventPriority): Lane { + return updatePriority; +} + export function lanesToEventPriority(lanes: Lanes): EventPriority { const lane = getHighestPriorityLane(lanes); if (!isHigherEventPriority(DiscreteEventPriority, lane)) { diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index a3b90d41de424..aae7f073110b6 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -674,7 +674,7 @@ function updateOffscreenComponent( // pending work. We can't read `childLanes` from the current Offscreen // fiber because we reset it when it was deferred; however, we can read // the pending lanes from the child fibers. - let currentChildLanes = NoLanes; + let currentChildLanes: Lanes = NoLanes; while (currentChild !== null) { currentChildLanes = mergeLanes( mergeLanes(currentChildLanes, currentChild.lanes), diff --git a/packages/react-reconciler/src/ReactFiberClassUpdateQueue.js b/packages/react-reconciler/src/ReactFiberClassUpdateQueue.js index d7a1efbb47f4a..7945e4fb1c915 100644 --- a/packages/react-reconciler/src/ReactFiberClassUpdateQueue.js +++ b/packages/react-reconciler/src/ReactFiberClassUpdateQueue.js @@ -556,7 +556,7 @@ export function processUpdateQueue( let newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes // from the original lanes. - let newLanes = NoLanes; + let newLanes: Lanes = NoLanes; let newBaseState = null; let newFirstBaseUpdate = null; diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js index 51e21b8d2f480..319c8f5dab5d1 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js @@ -742,7 +742,7 @@ function bubbleProperties(completedWork: Fiber) { completedWork.alternate !== null && completedWork.alternate.child === completedWork.child; - let newChildLanes = NoLanes; + let newChildLanes: Lanes = NoLanes; let subtreeFlags = NoFlags; if (!didBailout) { diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index 0d86c2e1c5750..0d4e803a7a130 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -27,7 +27,11 @@ import type {HookFlags} from './ReactHookEffectTags'; import type {Flags} from './ReactFiberFlags'; import type {TransitionStatus} from './ReactFiberConfig'; -import {NotPendingTransition as NoPendingHostTransition} from './ReactFiberConfig'; +import { + NotPendingTransition as NoPendingHostTransition, + setCurrentUpdatePriority, + getCurrentUpdatePriority, +} from './ReactFiberConfig'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import { enableDebugTracing, @@ -74,8 +78,6 @@ import { } from './ReactFiberLane'; import { ContinuousEventPriority, - getCurrentUpdatePriority, - setCurrentUpdatePriority, higherEventPriority, } from './ReactEventPriorities'; import {readContext, checkIfContextChanged} from './ReactFiberNewContext'; diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index 7e056f2e71068..cde23ef9a6249 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -223,7 +223,7 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { return NoLanes; } - let nextLanes = NoLanes; + let nextLanes: Lanes = NoLanes; const suspendedLanes = root.suspendedLanes; const pingedLanes = root.pingedLanes; diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index 542cfd36b14da..06100010d0ee3 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -86,10 +86,6 @@ import { getHighestPriorityPendingLanes, higherPriorityLane, } from './ReactFiberLane'; -import { - getCurrentUpdatePriority, - runWithPriority, -} from './ReactEventPriorities'; import { scheduleRefresh, scheduleRoot, @@ -525,8 +521,6 @@ export function attemptHydrationAtCurrentPriority(fiber: Fiber): void { markRetryLaneIfNotHydrated(fiber, lane); } -export {getCurrentUpdatePriority, runWithPriority}; - export {findHostInstance}; export {findHostInstanceWithWarning}; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 41d9bcdeaf8bf..47dd2f024ca04 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -70,11 +70,13 @@ import { cancelTimeout, noTimeout, afterActiveInstanceBlur, - getCurrentEventPriority, startSuspendingCommit, waitForCommitToBeReady, preloadInstance, supportsHydration, + setCurrentUpdatePriority, + getCurrentUpdatePriority, + resolveUpdatePriority, } from './ReactFiberConfig'; import {createWorkInProgress, resetWorkInProgress} from './ReactFiber'; @@ -157,10 +159,9 @@ import { import { DiscreteEventPriority, DefaultEventPriority, - getCurrentUpdatePriority, - setCurrentUpdatePriority, lowerEventPriority, lanesToEventPriority, + eventPriorityToLane, } from './ReactEventPriorities'; import {requestCurrentTransition} from './ReactFiberTransition'; import { @@ -641,25 +642,7 @@ export function requestUpdateLane(fiber: Fiber): Lane { requestTransitionLane(transition); } - // 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; - } - - // 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; + return eventPriorityToLane(resolveUpdatePriority()); } function requestRetryLane(fiber: Fiber) { @@ -1446,12 +1429,12 @@ export function getExecutionContext(): ExecutionContext { } export function deferredUpdates(fn: () => A): A { - const previousPriority = getCurrentUpdatePriority(); const prevTransition = ReactCurrentBatchConfig.transition; + const previousPriority = getCurrentUpdatePriority(); try { - ReactCurrentBatchConfig.transition = null; setCurrentUpdatePriority(DefaultEventPriority); + ReactCurrentBatchConfig.transition = null; return fn(); } finally { setCurrentUpdatePriority(previousPriority); @@ -1492,11 +1475,11 @@ export function discreteUpdates( c: C, d: D, ): R { - const previousPriority = getCurrentUpdatePriority(); const prevTransition = ReactCurrentBatchConfig.transition; + const previousPriority = getCurrentUpdatePriority(); try { - ReactCurrentBatchConfig.transition = null; setCurrentUpdatePriority(DiscreteEventPriority); + ReactCurrentBatchConfig.transition = null; return fn(a, b, c, d); } finally { setCurrentUpdatePriority(previousPriority); @@ -1533,8 +1516,8 @@ export function flushSync(fn: (() => R) | void): R | void { const previousPriority = getCurrentUpdatePriority(); try { - ReactCurrentBatchConfig.transition = null; setCurrentUpdatePriority(DiscreteEventPriority); + ReactCurrentBatchConfig.transition = null; if (fn) { return fn(); } else { @@ -2713,12 +2696,12 @@ function commitRoot( ) { // TODO: This no longer makes any sense. We already wrap the mutation and // layout phases. Should be able to remove. - const previousUpdateLanePriority = getCurrentUpdatePriority(); const prevTransition = ReactCurrentBatchConfig.transition; + const previousUpdateLanePriority = getCurrentUpdatePriority(); try { - ReactCurrentBatchConfig.transition = null; setCurrentUpdatePriority(DiscreteEventPriority); + ReactCurrentBatchConfig.transition = null; commitRootImpl( root, recoverableErrors, @@ -3187,8 +3170,8 @@ export function flushPassiveEffects(): boolean { const previousPriority = getCurrentUpdatePriority(); try { - ReactCurrentBatchConfig.transition = null; setCurrentUpdatePriority(priority); + ReactCurrentBatchConfig.transition = null; return flushPassiveEffectsImpl(); } finally { setCurrentUpdatePriority(previousPriority); @@ -3543,7 +3526,7 @@ function retryTimedOutBoundary(boundaryFiber: Fiber, retryLane: Lane) { export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) { const suspenseState: null | SuspenseState = boundaryFiber.memoizedState; - let retryLane = NoLane; + let retryLane: Lane = NoLane; if (suspenseState !== null) { retryLane = suspenseState.retryLane; } @@ -3551,7 +3534,7 @@ export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) { } export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) { - let retryLane = NoLane; // Default + let retryLane: Lane = NoLane; // Default let retryCache: WeakSet | Set | null; switch (boundaryFiber.tag) { case SuspenseComponent: diff --git a/packages/react-reconciler/src/ReactReconcilerConstants.js b/packages/react-reconciler/src/ReactReconcilerConstants.js index 3e9b1c7009da9..7c650048ddce7 100644 --- a/packages/react-reconciler/src/ReactReconcilerConstants.js +++ b/packages/react-reconciler/src/ReactReconcilerConstants.js @@ -11,6 +11,7 @@ // Only expose the minimal subset necessary to implement a host config. export { + NoEventPriority, DiscreteEventPriority, ContinuousEventPriority, DefaultEventPriority, diff --git a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js index 0a38182ecbe54..753c2d849b19a 100644 --- a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js @@ -15,6 +15,7 @@ let act; let ReactFiberReconciler; let ConcurrentRoot; let DefaultEventPriority; +let NoEventPriority; describe('ReactFiberHostContext', () => { beforeEach(() => { @@ -26,6 +27,8 @@ describe('ReactFiberHostContext', () => { require('react-reconciler/src/ReactRootTags').ConcurrentRoot; DefaultEventPriority = require('react-reconciler/src/ReactEventPriorities').DefaultEventPriority; + NoEventPriority = + require('react-reconciler/src/ReactEventPriorities').NoEventPriority; }); global.IS_REACT_ACT_ENVIRONMENT = true; @@ -34,6 +37,7 @@ describe('ReactFiberHostContext', () => { it('should send the context to prepareForCommit and resetAfterCommit', () => { const rootContext = {}; const childContext = {}; + let updatePriority: typeof DefaultEventPriority = NoEventPriority; const Renderer = ReactFiberReconciler({ prepareForCommit: function (hostContext) { expect(hostContext).toBe(rootContext); @@ -67,7 +71,16 @@ describe('ReactFiberHostContext', () => { return null; }, clearContainer: function () {}, - getCurrentEventPriority: function () { + setCurrentUpdatePriority: function (newPriority: any) { + updatePriority = newPriority; + }, + getCurrentUpdatePriority: function () { + return updatePriority; + }, + resolveUpdatePriority: function () { + if (updatePriority !== NoEventPriority) { + return updatePriority; + } return DefaultEventPriority; }, shouldAttemptEagerTransition() { diff --git a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js index 492b1a4a8906f..348a70564c1b7 100644 --- a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js +++ b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js @@ -65,7 +65,9 @@ export const afterActiveInstanceBlur = $$$config.afterActiveInstanceBlur; export const preparePortalMount = $$$config.preparePortalMount; export const prepareScopeUpdate = $$$config.prepareScopeUpdate; export const getInstanceFromScope = $$$config.getInstanceFromScope; -export const getCurrentEventPriority = $$$config.getCurrentEventPriority; +export const setCurrentUpdatePriority = $$$config.setCurrentUpdatePriority; +export const getCurrentUpdatePriority = $$$config.getCurrentUpdatePriority; +export const resolveUpdatePriority = $$$config.resolveUpdatePriority; export const shouldAttemptEagerTransition = $$$config.shouldAttemptEagerTransition; export const detachDeletedInstance = $$$config.detachDeletedInstance; diff --git a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js index e374b25922b99..b20d2054f1002 100644 --- a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js +++ b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js @@ -10,6 +10,7 @@ import isArray from 'shared/isArray'; import { DefaultEventPriority, + NoEventPriority, type EventPriority, } from 'react-reconciler/src/ReactEventPriorities'; @@ -201,7 +202,19 @@ export function createTextInstance( }; } -export function getCurrentEventPriority(): EventPriority { +let currentUpdatePriority: EventPriority = NoEventPriority; +export function setCurrentUpdatePriority(newPriority: EventPriority): void { + currentUpdatePriority = newPriority; +} + +export function getCurrentUpdatePriority(): EventPriority { + return currentUpdatePriority; +} + +export function resolveUpdatePriority(): EventPriority { + if (currentUpdatePriority !== NoEventPriority) { + return currentUpdatePriority; + } return DefaultEventPriority; } export function shouldAttemptEagerTransition(): boolean {