Decouple update priority tracking from Scheduler package (#19121)

* Initial currentLanePriority implementation

* Minor updates from review

* Fix typos and enable flag

* Fix feature flags and lint

* Fix simple event tests by switching to withSuspenseConfig

* Don't lower the priority of setPending in startTransition below InputContinuous

* Move currentUpdateLanePriority in commit root into the first effect block

* Refactor requestUpdateLane to log for priority mismatches

Also verifies that the update lane priority matches the scheduler lane priority before using it

* Fix four tests by adding ReactDOM.unstable_runWithPriority

* Fix partial hydration when using update lane priority

* Fix partial hydration when using update lane priority

* Rename feature flag and only log for now

* Move unstable_runWithPriority to ReactFiberReconciler

* Add unstable_runWithPriority to ReactNoopPersistent too

* Bug fixes and performance improvements

* Initial currentLanePriority implementation

* Minor updates from review

* Fix typos and enable flag

* Remove higherLanePriority from ReactDOMEventReplaying.js

* Change warning implementation and startTransition update lane priority

* Inject reconciler functions to avoid importing src/

* Fix feature flags and lint

* Fix simple event tests by switching to withSuspenseConfig

* Don't lower the priority of setPending in startTransition below InputContinuous

* Move currentUpdateLanePriority in commit root into the first effect block

* Refactor requestUpdateLane to log for priority mismatches

Also verifies that the update lane priority matches the scheduler lane priority before using it

* Fix four tests by adding ReactDOM.unstable_runWithPriority

* Fix partial hydration when using update lane priority

* Fix partial hydration when using update lane priority

* Rename feature flag and only log for now

* Move unstable_runWithPriority to ReactFiberReconciler

* Bug fixes and performance improvements

* Remove higherLanePriority from ReactDOMEventReplaying.js

* Change warning implementation and startTransition update lane priority

* Inject reconciler functions to avoid importing src/

* Fixes from bad rebase
This commit is contained in:
Ricky 2020-07-06 18:53:42 -04:00 committed by GitHub
parent c3e42a962b
commit 91a2e8173f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 396 additions and 67 deletions

View File

@ -34,6 +34,7 @@ export {
createBlockingRoot as unstable_createBlockingRoot, createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled, unstable_flushControlled,
unstable_scheduleHydration, unstable_scheduleHydration,
unstable_runWithPriority,
unstable_renderSubtreeIntoContainer, unstable_renderSubtreeIntoContainer,
unstable_createPortal, unstable_createPortal,
unstable_createEventHandle, unstable_createEventHandle,

View File

@ -23,6 +23,8 @@ export {
createBlockingRoot as unstable_createBlockingRoot, createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled, unstable_flushControlled,
unstable_scheduleHydration, unstable_scheduleHydration,
// DO NOT USE: Temporarily exposing this to migrate off of Scheduler.runWithPriority.
unstable_runWithPriority,
// Disabled behind disableUnstableRenderSubtreeIntoContainer // Disabled behind disableUnstableRenderSubtreeIntoContainer
unstable_renderSubtreeIntoContainer, unstable_renderSubtreeIntoContainer,
// Disabled behind disableUnstableCreatePortal // Disabled behind disableUnstableCreatePortal

View File

@ -25,6 +25,7 @@ export {
createBlockingRoot as unstable_createBlockingRoot, createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled, unstable_flushControlled,
unstable_scheduleHydration, unstable_scheduleHydration,
unstable_runWithPriority,
unstable_renderSubtreeIntoContainer, unstable_renderSubtreeIntoContainer,
unstable_createPortal, unstable_createPortal,
unstable_createEventHandle, unstable_createEventHandle,

View File

@ -19,6 +19,7 @@ export {
createBlockingRoot as unstable_createBlockingRoot, createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled, unstable_flushControlled,
unstable_scheduleHydration, unstable_scheduleHydration,
unstable_runWithPriority,
unstable_createEventHandle, unstable_createEventHandle,
unstable_isNewReconciler, unstable_isNewReconciler,
} from './src/client/ReactDOM'; } from './src/client/ReactDOM';

View File

@ -35,6 +35,8 @@ import {
attemptUserBlockingHydration, attemptUserBlockingHydration,
attemptContinuousHydration, attemptContinuousHydration,
attemptHydrationAtCurrentPriority, attemptHydrationAtCurrentPriority,
runWithPriority,
getCurrentUpdatePriority,
} from 'react-reconciler/src/ReactFiberReconciler'; } from 'react-reconciler/src/ReactFiberReconciler';
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal'; import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
import {canUseDOM} from 'shared/ExecutionEnvironment'; import {canUseDOM} from 'shared/ExecutionEnvironment';
@ -58,6 +60,8 @@ import {
setAttemptContinuousHydration, setAttemptContinuousHydration,
setAttemptHydrationAtCurrentPriority, setAttemptHydrationAtCurrentPriority,
queueExplicitHydrationTarget, queueExplicitHydrationTarget,
setGetCurrentUpdatePriority,
setAttemptHydrationAtPriority,
} from '../events/ReactDOMEventReplaying'; } from '../events/ReactDOMEventReplaying';
import {setBatchingImplementation} from '../events/ReactDOMUpdateBatching'; import {setBatchingImplementation} from '../events/ReactDOMUpdateBatching';
import { import {
@ -70,6 +74,8 @@ setAttemptSynchronousHydration(attemptSynchronousHydration);
setAttemptUserBlockingHydration(attemptUserBlockingHydration); setAttemptUserBlockingHydration(attemptUserBlockingHydration);
setAttemptContinuousHydration(attemptContinuousHydration); setAttemptContinuousHydration(attemptContinuousHydration);
setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority); setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority);
setGetCurrentUpdatePriority(getCurrentUpdatePriority);
setAttemptHydrationAtPriority(runWithPriority);
let didWarnAboutUnstableCreatePortal = false; let didWarnAboutUnstableCreatePortal = false;
let didWarnAboutUnstableRenderSubtreeIntoContainer = false; let didWarnAboutUnstableRenderSubtreeIntoContainer = false;
@ -205,6 +211,9 @@ export {
unstable_createPortal, unstable_createPortal,
// enableCreateEventHandleAPI // enableCreateEventHandleAPI
createEventHandle as unstable_createEventHandle, createEventHandle as unstable_createEventHandle,
// TODO: Remove this once callers migrate to alternatives.
// This should only be used by React internals.
runWithPriority as unstable_runWithPriority,
}; };
const foundDevTools = injectIntoDevTools({ const foundDevTools = injectIntoDevTools({

View File

@ -12,7 +12,10 @@ import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes'; import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {ElementListenerMap} from '../client/ReactDOMComponentTree'; import type {ElementListenerMap} from '../client/ReactDOMComponentTree';
import type {EventSystemFlags} from './EventSystemFlags'; import type {EventSystemFlags} from './EventSystemFlags';
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes'; import type {
FiberRoot,
ReactPriorityLevel,
} from 'react-reconciler/src/ReactInternalTypes';
import { import {
enableDeprecatedFlareAPI, enableDeprecatedFlareAPI,
@ -64,6 +67,23 @@ export function setAttemptHydrationAtCurrentPriority(
attemptHydrationAtCurrentPriority = fn; attemptHydrationAtCurrentPriority = fn;
} }
let getCurrentUpdatePriority: () => ReactPriorityLevel;
export function setGetCurrentUpdatePriority(fn: () => ReactPriorityLevel) {
getCurrentUpdatePriority = fn;
}
let attemptHydrationAtPriority: <T>(
priority: ReactPriorityLevel,
fn: () => T,
) => T;
export function setAttemptHydrationAtPriority(
fn: <T>(priority: ReactPriorityLevel, fn: () => T) => T,
) {
attemptHydrationAtPriority = fn;
}
// TODO: Upgrade this definition once we're on a newer version of Flow that // TODO: Upgrade this definition once we're on a newer version of Flow that
// has this definition built-in. // has this definition built-in.
type PointerEvent = Event & { type PointerEvent = Event & {
@ -147,6 +167,7 @@ type QueuedHydrationTarget = {|
blockedOn: null | Container | SuspenseInstance, blockedOn: null | Container | SuspenseInstance,
target: Node, target: Node,
priority: number, priority: number,
lanePriority: ReactPriorityLevel,
|}; |};
const queuedExplicitHydrationTargets: Array<QueuedHydrationTarget> = []; const queuedExplicitHydrationTargets: Array<QueuedHydrationTarget> = [];
@ -508,9 +529,12 @@ function attemptExplicitHydrationTarget(
// We're blocked on hydrating this boundary. // We're blocked on hydrating this boundary.
// Increase its priority. // Increase its priority.
queuedTarget.blockedOn = instance; queuedTarget.blockedOn = instance;
runWithPriority(queuedTarget.priority, () => { attemptHydrationAtPriority(queuedTarget.lanePriority, () => {
attemptHydrationAtCurrentPriority(nearestMounted); runWithPriority(queuedTarget.priority, () => {
attemptHydrationAtCurrentPriority(nearestMounted);
});
}); });
return; return;
} }
} else if (tag === HostRoot) { } else if (tag === HostRoot) {
@ -529,15 +553,17 @@ function attemptExplicitHydrationTarget(
export function queueExplicitHydrationTarget(target: Node): void { export function queueExplicitHydrationTarget(target: Node): void {
if (enableSelectiveHydration) { if (enableSelectiveHydration) {
const priority = getCurrentPriorityLevel(); const schedulerPriority = getCurrentPriorityLevel();
const updateLanePriority = getCurrentUpdatePriority();
const queuedTarget: QueuedHydrationTarget = { const queuedTarget: QueuedHydrationTarget = {
blockedOn: null, blockedOn: null,
target: target, target: target,
priority: priority, priority: schedulerPriority,
lanePriority: updateLanePriority,
}; };
let i = 0; let i = 0;
for (; i < queuedExplicitHydrationTargets.length; i++) { for (; i < queuedExplicitHydrationTargets.length; i++) {
if (priority <= queuedExplicitHydrationTargets[i].priority) { if (schedulerPriority <= queuedExplicitHydrationTargets[i].priority) {
break; break;
} }
} }

View File

@ -231,6 +231,8 @@ describe('SimpleEventPlugin', function() {
describe('interactive events, in concurrent mode', () => { describe('interactive events, in concurrent mode', () => {
beforeEach(() => { beforeEach(() => {
jest.resetModules(); jest.resetModules();
React = require('react');
ReactDOM = require('react-dom'); ReactDOM = require('react-dom');
Scheduler = require('scheduler'); Scheduler = require('scheduler');
}); });
@ -377,11 +379,14 @@ describe('SimpleEventPlugin', function() {
<button <button
ref={el => (button = el)} ref={el => (button = el)}
onClick={() => { onClick={() => {
Scheduler.unstable_next(() => { React.unstable_withSuspenseConfig(
this.setState(state => ({ () => {
lowPriCount: state.lowPriCount + 1, this.setState(state => ({
})); lowPriCount: state.lowPriCount + 1,
}); }));
},
{timeoutMs: 5000},
);
}}> }}>
{text} {text}
</button> </button>

View File

@ -47,6 +47,9 @@ export const {
act, act,
dumpTree, dumpTree,
getRoot, getRoot,
// TODO: Remove this once callers migrate to alternatives.
// This should only be used by React internals.
unstable_runWithPriority,
} = createReactNoop( } = createReactNoop(
ReactFiberReconciler, // reconciler ReactFiberReconciler, // reconciler
true, // useMutation true, // useMutation

View File

@ -47,6 +47,9 @@ export const {
act, act,
dumpTree, dumpTree,
getRoot, getRoot,
// TODO: Remove this once callers migrate to alternatives.
// This should only be used by React internals.
unstable_runWithPriority,
} = createReactNoop( } = createReactNoop(
ReactFiberReconciler, // reconciler ReactFiberReconciler, // reconciler
false, // useMutation false, // useMutation

View File

@ -954,6 +954,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
return Scheduler.unstable_flushExpired(); return Scheduler.unstable_flushExpired();
}, },
unstable_runWithPriority: NoopRenderer.runWithPriority,
batchedUpdates: NoopRenderer.batchedUpdates, batchedUpdates: NoopRenderer.batchedUpdates,
deferredUpdates: NoopRenderer.deferredUpdates, deferredUpdates: NoopRenderer.deferredUpdates,

View File

@ -30,11 +30,16 @@ import {NoMode, BlockingMode} from './ReactTypeOfMode';
import { import {
NoLane, NoLane,
NoLanes, NoLanes,
InputContinuousLanePriority,
isSubsetOfLanes, isSubsetOfLanes,
mergeLanes, mergeLanes,
removeLanes, removeLanes,
markRootEntangled, markRootEntangled,
markRootMutableRead, markRootMutableRead,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
higherLanePriority,
DefaultLanePriority,
} from './ReactFiberLane'; } from './ReactFiberLane';
import {readContext} from './ReactFiberNewContext.new'; import {readContext} from './ReactFiberNewContext.new';
import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.new'; import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.new';
@ -1498,12 +1503,20 @@ function rerenderDeferredValue<T>(
function startTransition(setPending, config, callback) { function startTransition(setPending, config, callback) {
const priorityLevel = getCurrentPriorityLevel(); const priorityLevel = getCurrentPriorityLevel();
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
runWithPriority( runWithPriority(
priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel, priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
() => { () => {
setPending(true); setPending(true);
}, },
); );
// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);
runWithPriority( runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel, priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => { () => {
@ -1513,6 +1526,7 @@ function startTransition(setPending, config, callback) {
setPending(false); setPending(false);
callback(); callback();
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
ReactCurrentBatchConfig.suspense = previousConfig; ReactCurrentBatchConfig.suspense = previousConfig;
} }
}, },

View File

@ -33,11 +33,16 @@ import {NoMode, BlockingMode, DebugTracingMode} from './ReactTypeOfMode';
import { import {
NoLane, NoLane,
NoLanes, NoLanes,
InputContinuousLanePriority,
isSubsetOfLanes, isSubsetOfLanes,
mergeLanes, mergeLanes,
removeLanes, removeLanes,
markRootEntangled, markRootEntangled,
markRootMutableRead, markRootMutableRead,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
higherLanePriority,
DefaultLanePriority,
} from './ReactFiberLane'; } from './ReactFiberLane';
import {readContext} from './ReactFiberNewContext.old'; import {readContext} from './ReactFiberNewContext.old';
import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.old'; import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.old';
@ -1502,12 +1507,20 @@ function rerenderDeferredValue<T>(
function startTransition(setPending, config, callback) { function startTransition(setPending, config, callback) {
const priorityLevel = getCurrentPriorityLevel(); const priorityLevel = getCurrentPriorityLevel();
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
runWithPriority( runWithPriority(
priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel, priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
() => { () => {
setPending(true); setPending(true);
}, },
); );
// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);
runWithPriority( runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel, priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => { () => {
@ -1517,6 +1530,7 @@ function startTransition(setPending, config, callback) {
setPending(false); setPending(false);
callback(); callback();
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
ReactCurrentBatchConfig.suspense = previousConfig; ReactCurrentBatchConfig.suspense = previousConfig;
} }
}, },

View File

@ -49,10 +49,10 @@ const InputDiscreteHydrationLanePriority: LanePriority = 14;
export const InputDiscreteLanePriority: LanePriority = 13; export const InputDiscreteLanePriority: LanePriority = 13;
const InputContinuousHydrationLanePriority: LanePriority = 12; const InputContinuousHydrationLanePriority: LanePriority = 12;
const InputContinuousLanePriority: LanePriority = 11; export const InputContinuousLanePriority: LanePriority = 11;
const DefaultHydrationLanePriority: LanePriority = 10; const DefaultHydrationLanePriority: LanePriority = 10;
const DefaultLanePriority: LanePriority = 9; export const DefaultLanePriority: LanePriority = 9;
const TransitionShortHydrationLanePriority: LanePriority = 8; const TransitionShortHydrationLanePriority: LanePriority = 8;
export const TransitionShortLanePriority: LanePriority = 7; export const TransitionShortLanePriority: LanePriority = 7;
@ -120,6 +120,16 @@ export const OffscreenLane: Lane = /* */ 0b1000000000000000000
export const NoTimestamp = -1; export const NoTimestamp = -1;
let currentUpdateLanePriority: LanePriority = NoLanePriority;
export function getCurrentUpdateLanePriority(): LanePriority {
return currentUpdateLanePriority;
}
export function setCurrentUpdateLanePriority(newLanePriority: LanePriority) {
currentUpdateLanePriority = newLanePriority;
}
// "Registers" used to "return" multiple values // "Registers" used to "return" multiple values
// Used by getHighestPriorityLanes and getNextLanes: // Used by getHighestPriorityLanes and getNextLanes:
let return_highestLanePriority: LanePriority = DefaultLanePriority; let return_highestLanePriority: LanePriority = DefaultLanePriority;
@ -651,6 +661,13 @@ export function higherPriorityLane(a: Lane, b: Lane) {
return a !== NoLane && a < b ? a : b; return a !== NoLane && a < b ? a : b;
} }
export function higherLanePriority(
a: LanePriority,
b: LanePriority,
): LanePriority {
return a !== NoLanePriority && a > b ? a : b;
}
export function createLaneMap<T>(initial: T): LaneMap<T> { export function createLaneMap<T>(initial: T): LaneMap<T> {
return new Array(TotalLanes).fill(initial); return new Array(TotalLanes).fill(initial);
} }

View File

@ -50,6 +50,8 @@ import {
focusWithin as focusWithin_old, focusWithin as focusWithin_old,
observeVisibleRects as observeVisibleRects_old, observeVisibleRects as observeVisibleRects_old,
registerMutableSourceForHydration as registerMutableSourceForHydration_old, registerMutableSourceForHydration as registerMutableSourceForHydration_old,
runWithPriority as runWithPriority_old,
getCurrentUpdatePriority as getCurrentUpdatePriority_old,
} from './ReactFiberReconciler.old'; } from './ReactFiberReconciler.old';
import { import {
@ -88,6 +90,8 @@ import {
focusWithin as focusWithin_new, focusWithin as focusWithin_new,
observeVisibleRects as observeVisibleRects_new, observeVisibleRects as observeVisibleRects_new,
registerMutableSourceForHydration as registerMutableSourceForHydration_new, registerMutableSourceForHydration as registerMutableSourceForHydration_new,
runWithPriority as runWithPriority_new,
getCurrentUpdatePriority as getCurrentUpdatePriority_new,
} from './ReactFiberReconciler.new'; } from './ReactFiberReconciler.new';
export const createContainer = enableNewReconciler export const createContainer = enableNewReconciler
@ -139,6 +143,9 @@ export const attemptContinuousHydration = enableNewReconciler
export const attemptHydrationAtCurrentPriority = enableNewReconciler export const attemptHydrationAtCurrentPriority = enableNewReconciler
? attemptHydrationAtCurrentPriority_new ? attemptHydrationAtCurrentPriority_new
: attemptHydrationAtCurrentPriority_old; : attemptHydrationAtCurrentPriority_old;
export const getCurrentUpdatePriority = enableNewReconciler
? getCurrentUpdatePriority_new
: getCurrentUpdatePriority_old;
export const findHostInstance = enableNewReconciler export const findHostInstance = enableNewReconciler
? findHostInstance_new ? findHostInstance_new
: findHostInstance_old; : findHostInstance_old;
@ -194,3 +201,6 @@ export const observeVisibleRects = enableNewReconciler
export const registerMutableSourceForHydration = enableNewReconciler export const registerMutableSourceForHydration = enableNewReconciler
? registerMutableSourceForHydration_new ? registerMutableSourceForHydration_new
: registerMutableSourceForHydration_old; : registerMutableSourceForHydration_old;
export const runWithPriority = enableNewReconciler
? runWithPriority_new
: runWithPriority_old;

View File

@ -7,7 +7,11 @@
* @flow * @flow
*/ */
import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes'; import type {
Fiber,
ReactPriorityLevel,
SuspenseHydrationCallbacks,
} from './ReactInternalTypes';
import type {FiberRoot} from './ReactInternalTypes'; import type {FiberRoot} from './ReactInternalTypes';
import type {RootTag} from './ReactRootTags'; import type {RootTag} from './ReactRootTags';
import type { import type {
@ -79,6 +83,10 @@ import {
NoTimestamp, NoTimestamp,
getHighestPriorityPendingLanes, getHighestPriorityPendingLanes,
higherPriorityLane, higherPriorityLane,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
schedulerPriorityToLanePriority,
lanePriorityToSchedulerPriority,
} from './ReactFiberLane'; } from './ReactFiberLane';
import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig'; import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig';
import { import {
@ -424,6 +432,20 @@ export function attemptHydrationAtCurrentPriority(fiber: Fiber): void {
markRetryLaneIfNotHydrated(fiber, lane); markRetryLaneIfNotHydrated(fiber, lane);
} }
export function runWithPriority<T>(priority: ReactPriorityLevel, fn: () => T) {
const previousPriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(schedulerPriorityToLanePriority(priority));
return fn();
} finally {
setCurrentUpdateLanePriority(previousPriority);
}
}
export function getCurrentUpdatePriority(): ReactPriorityLevel {
return lanePriorityToSchedulerPriority(getCurrentUpdateLanePriority());
}
export {findHostInstance}; export {findHostInstance};
export {findHostInstanceWithWarning}; export {findHostInstanceWithWarning};

View File

@ -7,7 +7,11 @@
* @flow * @flow
*/ */
import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes'; import type {
Fiber,
ReactPriorityLevel,
SuspenseHydrationCallbacks,
} from './ReactInternalTypes';
import type {FiberRoot} from './ReactInternalTypes'; import type {FiberRoot} from './ReactInternalTypes';
import type {RootTag} from './ReactRootTags'; import type {RootTag} from './ReactRootTags';
import type { import type {
@ -79,6 +83,10 @@ import {
NoTimestamp, NoTimestamp,
getHighestPriorityPendingLanes, getHighestPriorityPendingLanes,
higherPriorityLane, higherPriorityLane,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
schedulerPriorityToLanePriority,
lanePriorityToSchedulerPriority,
} from './ReactFiberLane'; } from './ReactFiberLane';
import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig'; import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig';
import { import {
@ -424,6 +432,20 @@ export function attemptHydrationAtCurrentPriority(fiber: Fiber): void {
markRetryLaneIfNotHydrated(fiber, lane); markRetryLaneIfNotHydrated(fiber, lane);
} }
export function runWithPriority<T>(priority: ReactPriorityLevel, fn: () => T) {
const previousPriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(schedulerPriorityToLanePriority(priority));
return fn();
} finally {
setCurrentUpdateLanePriority(previousPriority);
}
}
export function getCurrentUpdatePriority(): ReactPriorityLevel {
return lanePriorityToSchedulerPriority(getCurrentUpdateLanePriority());
}
export {findHostInstance}; export {findHostInstance};
export {findHostInstanceWithWarning}; export {findHostInstanceWithWarning};

View File

@ -26,6 +26,7 @@ import {
enableSchedulerTracing, enableSchedulerTracing,
warnAboutUnmockedScheduler, warnAboutUnmockedScheduler,
deferRenderPhaseUpdateToNextBatch, deferRenderPhaseUpdateToNextBatch,
decoupleUpdatePriorityFromScheduler,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactSharedInternals from 'shared/ReactSharedInternals';
import invariant from 'shared/invariant'; import invariant from 'shared/invariant';
@ -113,6 +114,7 @@ import {
InputDiscreteLanePriority, InputDiscreteLanePriority,
TransitionShortLanePriority, TransitionShortLanePriority,
TransitionLongLanePriority, TransitionLongLanePriority,
DefaultLanePriority,
NoLanes, NoLanes,
NoLane, NoLane,
SyncLane, SyncLane,
@ -130,6 +132,8 @@ import {
hasUpdatePriority, hasUpdatePriority,
getNextLanes, getNextLanes,
returnNextLanesPriority, returnNextLanesPriority,
setCurrentUpdateLanePriority,
getCurrentUpdateLanePriority,
markStarvedLanesAsExpired, markStarvedLanesAsExpired,
getLanesToRetrySynchronouslyOnError, getLanesToRetrySynchronouslyOnError,
markRootUpdated, markRootUpdated,
@ -394,7 +398,6 @@ export function requestUpdateLane(
currentEventWipLanes = workInProgressRootIncludedLanes; currentEventWipLanes = workInProgressRootIncludedLanes;
} }
let lane;
if (suspenseConfig !== null) { if (suspenseConfig !== null) {
// Use the size of the timeout as a heuristic to prioritize shorter // Use the size of the timeout as a heuristic to prioritize shorter
// transitions over longer ones. // transitions over longer ones.
@ -412,26 +415,56 @@ export function requestUpdateLane(
: NoLanes; : NoLanes;
} }
lane = findTransitionLane( return findTransitionLane(
transitionLanePriority, transitionLanePriority,
currentEventWipLanes, currentEventWipLanes,
currentEventPendingLanes, currentEventPendingLanes,
); );
} else { }
// TODO: If we're not inside `runWithPriority`, this returns the priority
// of the currently running task. That's probably not what we want.
const schedulerPriority = getCurrentPriorityLevel();
if ( // TODO: Remove this dependency on the Scheduler priority.
// TODO: Temporary. We're removing the concept of discrete updates. // To do that, we're replacing it with an update lane priority.
(executionContext & DiscreteEventContext) !== NoContext && const schedulerPriority = getCurrentPriorityLevel();
schedulerPriority === UserBlockingSchedulerPriority
) { // The old behavior was using the priority level of the Scheduler.
lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes); // This couples React to the Scheduler internals, so we're replacing it
} else { // with the currentUpdateLanePriority above. As an example of how this
const lanePriority = schedulerPriorityToLanePriority(schedulerPriority); // could be problematic, if we're not inside `Scheduler.runWithPriority`,
lane = findUpdateLane(lanePriority, currentEventWipLanes); // then we'll get the priority of the current running Scheduler task,
// which is probably not what we want.
let lane;
if (
// TODO: Temporary. We're removing the concept of discrete updates.
(executionContext & DiscreteEventContext) !== NoContext &&
schedulerPriority === UserBlockingSchedulerPriority
) {
lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
} else {
const schedulerLanePriority = schedulerPriorityToLanePriority(
schedulerPriority,
);
if (decoupleUpdatePriorityFromScheduler) {
// In the new strategy, we will track the current update lane priority
// inside React and use that priority to select a lane for this update.
// For now, we're just logging when they're different so we can assess.
const currentUpdateLanePriority = getCurrentUpdateLanePriority();
if (
schedulerLanePriority !== currentUpdateLanePriority &&
currentUpdateLanePriority !== NoLanePriority
) {
if (__DEV__) {
console.error(
'Expected current scheduler lane priority %s to match current update lane priority %s',
schedulerLanePriority,
currentUpdateLanePriority,
);
}
}
} }
lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
} }
return lane; return lane;
@ -1068,7 +1101,13 @@ export function flushDiscreteUpdates() {
export function deferredUpdates<A>(fn: () => A): A { export function deferredUpdates<A>(fn: () => A): A {
// TODO: Remove in favor of Scheduler.next // TODO: Remove in favor of Scheduler.next
return runWithPriority(NormalSchedulerPriority, fn); const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(DefaultLanePriority);
return runWithPriority(NormalSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} }
function flushPendingDiscreteUpdates() { function flushPendingDiscreteUpdates() {
@ -1123,13 +1162,16 @@ export function discreteUpdates<A, B, C, D, R>(
): R { ): R {
const prevExecutionContext = executionContext; const prevExecutionContext = executionContext;
executionContext |= DiscreteEventContext; executionContext |= DiscreteEventContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
setCurrentUpdateLanePriority(InputDiscreteLanePriority);
// Should this // Should this
return runWithPriority( return runWithPriority(
UserBlockingSchedulerPriority, UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d), fn.bind(null, a, b, c, d),
); );
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
if (executionContext === NoContext) { if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch // Flush the immediate callbacks that were scheduled during this batch
@ -1166,13 +1208,16 @@ export function flushSync<A, R>(fn: A => R, a: A): R {
return fn(a); return fn(a);
} }
executionContext |= BatchedContext; executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
setCurrentUpdateLanePriority(SyncLanePriority);
if (fn) { if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a)); return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else { } else {
return (undefined: $FlowFixMe); return (undefined: $FlowFixMe);
} }
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch. // Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up // Note that this will happen even if batchedUpdates is higher up
@ -1184,9 +1229,12 @@ export function flushSync<A, R>(fn: A => R, a: A): R {
export function flushControlled(fn: () => mixed): void { export function flushControlled(fn: () => mixed): void {
const prevExecutionContext = executionContext; const prevExecutionContext = executionContext;
executionContext |= BatchedContext; executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediateSchedulerPriority, fn); runWithPriority(ImmediateSchedulerPriority, fn);
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
if (executionContext === NoContext) { if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch // Flush the immediate callbacks that were scheduled during this batch
@ -1867,6 +1915,9 @@ function commitRootImpl(root, renderPriorityLevel) {
} }
if (firstEffect !== null) { if (firstEffect !== null) {
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(SyncLanePriority);
const prevExecutionContext = executionContext; const prevExecutionContext = executionContext;
executionContext |= CommitContext; executionContext |= CommitContext;
const prevInteractions = pushInteractions(root); const prevInteractions = pushInteractions(root);
@ -1987,6 +2038,9 @@ function commitRootImpl(root, renderPriorityLevel) {
popInteractions(((prevInteractions: any): Set<Interaction>)); popInteractions(((prevInteractions: any): Set<Interaction>));
} }
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
// Reset the priority to the previous non-sync value.
setCurrentUpdateLanePriority(previousLanePriority);
} else { } else {
// No effects. // No effects.
root.current = finishedWork; root.current = finishedWork;
@ -2249,7 +2303,15 @@ export function flushPassiveEffects() {
? NormalSchedulerPriority ? NormalSchedulerPriority
: pendingPassiveEffectsRenderPriority; : pendingPassiveEffectsRenderPriority;
pendingPassiveEffectsRenderPriority = NoSchedulerPriority; pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
return runWithPriority(priorityLevel, flushPassiveEffectsImpl); const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} }
} }

View File

@ -26,6 +26,7 @@ import {
enableSchedulerTracing, enableSchedulerTracing,
warnAboutUnmockedScheduler, warnAboutUnmockedScheduler,
deferRenderPhaseUpdateToNextBatch, deferRenderPhaseUpdateToNextBatch,
decoupleUpdatePriorityFromScheduler,
enableDebugTracing, enableDebugTracing,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactSharedInternals from 'shared/ReactSharedInternals';
@ -124,6 +125,7 @@ import {
InputDiscreteLanePriority, InputDiscreteLanePriority,
TransitionShortLanePriority, TransitionShortLanePriority,
TransitionLongLanePriority, TransitionLongLanePriority,
DefaultLanePriority,
NoLanes, NoLanes,
NoLane, NoLane,
SyncLane, SyncLane,
@ -141,6 +143,8 @@ import {
hasUpdatePriority, hasUpdatePriority,
getNextLanes, getNextLanes,
returnNextLanesPriority, returnNextLanesPriority,
setCurrentUpdateLanePriority,
getCurrentUpdateLanePriority,
markStarvedLanesAsExpired, markStarvedLanesAsExpired,
getLanesToRetrySynchronouslyOnError, getLanesToRetrySynchronouslyOnError,
markRootUpdated, markRootUpdated,
@ -405,7 +409,6 @@ export function requestUpdateLane(
currentEventWipLanes = workInProgressRootIncludedLanes; currentEventWipLanes = workInProgressRootIncludedLanes;
} }
let lane;
if (suspenseConfig !== null) { if (suspenseConfig !== null) {
// Use the size of the timeout as a heuristic to prioritize shorter // Use the size of the timeout as a heuristic to prioritize shorter
// transitions over longer ones. // transitions over longer ones.
@ -423,26 +426,56 @@ export function requestUpdateLane(
: NoLanes; : NoLanes;
} }
lane = findTransitionLane( return findTransitionLane(
transitionLanePriority, transitionLanePriority,
currentEventWipLanes, currentEventWipLanes,
currentEventPendingLanes, currentEventPendingLanes,
); );
} else { }
// TODO: If we're not inside `runWithPriority`, this returns the priority
// of the currently running task. That's probably not what we want.
const schedulerPriority = getCurrentPriorityLevel();
if ( // TODO: Remove this dependency on the Scheduler priority.
// TODO: Temporary. We're removing the concept of discrete updates. // To do that, we're replacing it with an update lane priority.
(executionContext & DiscreteEventContext) !== NoContext && const schedulerPriority = getCurrentPriorityLevel();
schedulerPriority === UserBlockingSchedulerPriority
) { // The old behavior was using the priority level of the Scheduler.
lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes); // This couples React to the Scheduler internals, so we're replacing it
} else { // with the currentUpdateLanePriority above. As an example of how this
const lanePriority = schedulerPriorityToLanePriority(schedulerPriority); // could be problematic, if we're not inside `Scheduler.runWithPriority`,
lane = findUpdateLane(lanePriority, currentEventWipLanes); // then we'll get the priority of the current running Scheduler task,
// which is probably not what we want.
let lane;
if (
// TODO: Temporary. We're removing the concept of discrete updates.
(executionContext & DiscreteEventContext) !== NoContext &&
schedulerPriority === UserBlockingSchedulerPriority
) {
lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
} else {
const schedulerLanePriority = schedulerPriorityToLanePriority(
schedulerPriority,
);
if (decoupleUpdatePriorityFromScheduler) {
// In the new strategy, we will track the current update lane priority
// inside React and use that priority to select a lane for this update.
// For now, we're just logging when they're different so we can assess.
const currentUpdateLanePriority = getCurrentUpdateLanePriority();
if (
schedulerLanePriority !== currentUpdateLanePriority &&
currentUpdateLanePriority !== NoLanePriority
) {
if (__DEV__) {
console.error(
'Expected current scheduler lane priority %s to match current update lane priority %s',
schedulerLanePriority,
currentUpdateLanePriority,
);
}
}
} }
lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
} }
return lane; return lane;
@ -1079,7 +1112,13 @@ export function flushDiscreteUpdates() {
export function deferredUpdates<A>(fn: () => A): A { export function deferredUpdates<A>(fn: () => A): A {
// TODO: Remove in favor of Scheduler.next // TODO: Remove in favor of Scheduler.next
return runWithPriority(NormalSchedulerPriority, fn); const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(DefaultLanePriority);
return runWithPriority(NormalSchedulerPriority, fn);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} }
function flushPendingDiscreteUpdates() { function flushPendingDiscreteUpdates() {
@ -1134,13 +1173,16 @@ export function discreteUpdates<A, B, C, D, R>(
): R { ): R {
const prevExecutionContext = executionContext; const prevExecutionContext = executionContext;
executionContext |= DiscreteEventContext; executionContext |= DiscreteEventContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
setCurrentUpdateLanePriority(InputDiscreteLanePriority);
// Should this // Should this
return runWithPriority( return runWithPriority(
UserBlockingSchedulerPriority, UserBlockingSchedulerPriority,
fn.bind(null, a, b, c, d), fn.bind(null, a, b, c, d),
); );
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
if (executionContext === NoContext) { if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch // Flush the immediate callbacks that were scheduled during this batch
@ -1177,13 +1219,16 @@ export function flushSync<A, R>(fn: A => R, a: A): R {
return fn(a); return fn(a);
} }
executionContext |= BatchedContext; executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
setCurrentUpdateLanePriority(SyncLanePriority);
if (fn) { if (fn) {
return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a)); return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
} else { } else {
return (undefined: $FlowFixMe); return (undefined: $FlowFixMe);
} }
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
// Flush the immediate callbacks that were scheduled during this batch. // Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up // Note that this will happen even if batchedUpdates is higher up
@ -1195,9 +1240,12 @@ export function flushSync<A, R>(fn: A => R, a: A): R {
export function flushControlled(fn: () => mixed): void { export function flushControlled(fn: () => mixed): void {
const prevExecutionContext = executionContext; const prevExecutionContext = executionContext;
executionContext |= BatchedContext; executionContext |= BatchedContext;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediateSchedulerPriority, fn); runWithPriority(ImmediateSchedulerPriority, fn);
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
if (executionContext === NoContext) { if (executionContext === NoContext) {
// Flush the immediate callbacks that were scheduled during this batch // Flush the immediate callbacks that were scheduled during this batch
@ -1915,6 +1963,9 @@ function commitRootImpl(root, renderPriorityLevel) {
} }
if (firstEffect !== null) { if (firstEffect !== null) {
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(SyncLanePriority);
const prevExecutionContext = executionContext; const prevExecutionContext = executionContext;
executionContext |= CommitContext; executionContext |= CommitContext;
const prevInteractions = pushInteractions(root); const prevInteractions = pushInteractions(root);
@ -2035,6 +2086,9 @@ function commitRootImpl(root, renderPriorityLevel) {
popInteractions(((prevInteractions: any): Set<Interaction>)); popInteractions(((prevInteractions: any): Set<Interaction>));
} }
executionContext = prevExecutionContext; executionContext = prevExecutionContext;
// Reset the priority to the previous non-sync value.
setCurrentUpdateLanePriority(previousLanePriority);
} else { } else {
// No effects. // No effects.
root.current = finishedWork; root.current = finishedWork;
@ -2321,7 +2375,15 @@ export function flushPassiveEffects() {
? NormalSchedulerPriority ? NormalSchedulerPriority
: pendingPassiveEffectsRenderPriority; : pendingPassiveEffectsRenderPriority;
pendingPassiveEffectsRenderPriority = NoSchedulerPriority; pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
return runWithPriority(priorityLevel, flushPassiveEffectsImpl); const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
} }
} }

View File

@ -15,6 +15,11 @@ import * as Scheduler from 'scheduler';
import {__interactionsRef} from 'scheduler/tracing'; import {__interactionsRef} from 'scheduler/tracing';
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags'; import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant'; import invariant from 'shared/invariant';
import {
SyncLanePriority,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
} from './ReactFiberLane';
const { const {
unstable_runWithPriority: Scheduler_runWithPriority, unstable_runWithPriority: Scheduler_runWithPriority,
@ -171,9 +176,11 @@ function flushSyncCallbackQueueImpl() {
// Prevent re-entrancy. // Prevent re-entrancy.
isFlushingSyncQueue = true; isFlushingSyncQueue = true;
let i = 0; let i = 0;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
const isSync = true; const isSync = true;
const queue = syncQueue; const queue = syncQueue;
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediatePriority, () => { runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) { for (; i < queue.length; i++) {
let callback = queue[i]; let callback = queue[i];
@ -195,6 +202,7 @@ function flushSyncCallbackQueueImpl() {
); );
throw error; throw error;
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
isFlushingSyncQueue = false; isFlushingSyncQueue = false;
} }
} }

View File

@ -15,6 +15,11 @@ import * as Scheduler from 'scheduler';
import {__interactionsRef} from 'scheduler/tracing'; import {__interactionsRef} from 'scheduler/tracing';
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags'; import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant'; import invariant from 'shared/invariant';
import {
SyncLanePriority,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
} from './ReactFiberLane';
const { const {
unstable_runWithPriority: Scheduler_runWithPriority, unstable_runWithPriority: Scheduler_runWithPriority,
@ -171,9 +176,11 @@ function flushSyncCallbackQueueImpl() {
// Prevent re-entrancy. // Prevent re-entrancy.
isFlushingSyncQueue = true; isFlushingSyncQueue = true;
let i = 0; let i = 0;
const previousLanePriority = getCurrentUpdateLanePriority();
try { try {
const isSync = true; const isSync = true;
const queue = syncQueue; const queue = syncQueue;
setCurrentUpdateLanePriority(SyncLanePriority);
runWithPriority(ImmediatePriority, () => { runWithPriority(ImmediatePriority, () => {
for (; i < queue.length; i++) { for (; i < queue.length; i++) {
let callback = queue[i]; let callback = queue[i];
@ -195,6 +202,7 @@ function flushSyncCallbackQueueImpl() {
); );
throw error; throw error;
} finally { } finally {
setCurrentUpdateLanePriority(previousLanePriority);
isFlushingSyncQueue = false; isFlushingSyncQueue = false;
} }
} }

View File

@ -516,11 +516,16 @@ describe('ReactIncrementalUpdates', () => {
Scheduler.unstable_yieldValue('Committed: ' + log); Scheduler.unstable_yieldValue('Committed: ' + log);
if (log === 'B') { if (log === 'B') {
// Right after B commits, schedule additional updates. // Right after B commits, schedule additional updates.
Scheduler.unstable_runWithPriority( // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
ReactNoop.unstable_runWithPriority(
Scheduler.unstable_UserBlockingPriority, Scheduler.unstable_UserBlockingPriority,
() => { () =>
pushToLog('C'); Scheduler.unstable_runWithPriority(
}, Scheduler.unstable_UserBlockingPriority,
() => {
pushToLog('C');
},
),
); );
setLog(prevLog => prevLog + 'D'); setLog(prevLog => prevLog + 'D');
} }
@ -538,11 +543,17 @@ describe('ReactIncrementalUpdates', () => {
await ReactNoop.act(async () => { await ReactNoop.act(async () => {
pushToLog('A'); pushToLog('A');
Scheduler.unstable_runWithPriority(
// TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
ReactNoop.unstable_runWithPriority(
Scheduler.unstable_UserBlockingPriority, Scheduler.unstable_UserBlockingPriority,
() => { () =>
pushToLog('B'); Scheduler.unstable_runWithPriority(
}, Scheduler.unstable_UserBlockingPriority,
() => {
pushToLog('B');
},
),
); );
}); });
expect(Scheduler).toHaveYielded([ expect(Scheduler).toHaveYielded([
@ -574,11 +585,16 @@ describe('ReactIncrementalUpdates', () => {
Scheduler.unstable_yieldValue('Committed: ' + this.state.log); Scheduler.unstable_yieldValue('Committed: ' + this.state.log);
if (this.state.log === 'B') { if (this.state.log === 'B') {
// Right after B commits, schedule additional updates. // Right after B commits, schedule additional updates.
Scheduler.unstable_runWithPriority( // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
ReactNoop.unstable_runWithPriority(
Scheduler.unstable_UserBlockingPriority, Scheduler.unstable_UserBlockingPriority,
() => { () =>
this.pushToLog('C'); Scheduler.unstable_runWithPriority(
}, Scheduler.unstable_UserBlockingPriority,
() => {
this.pushToLog('C');
},
),
); );
this.pushToLog('D'); this.pushToLog('D');
} }
@ -598,11 +614,16 @@ describe('ReactIncrementalUpdates', () => {
await ReactNoop.act(async () => { await ReactNoop.act(async () => {
pushToLog('A'); pushToLog('A');
Scheduler.unstable_runWithPriority( // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
ReactNoop.unstable_runWithPriority(
Scheduler.unstable_UserBlockingPriority, Scheduler.unstable_UserBlockingPriority,
() => { () =>
pushToLog('B'); Scheduler.unstable_runWithPriority(
}, Scheduler.unstable_UserBlockingPriority,
() => {
pushToLog('B');
},
),
); );
}); });
expect(Scheduler).toHaveYielded([ expect(Scheduler).toHaveYielded([

View File

@ -232,9 +232,14 @@ describe('ReactDOMTracing', () => {
Scheduler.unstable_yieldValue('Child:update'); Scheduler.unstable_yieldValue('Child:update');
} else { } else {
Scheduler.unstable_yieldValue('Child:mount'); Scheduler.unstable_yieldValue('Child:mount');
Scheduler.unstable_runWithPriority( // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
ReactDOM.unstable_runWithPriority(
Scheduler.unstable_IdlePriority, Scheduler.unstable_IdlePriority,
() => setDidMount(true), () =>
Scheduler.unstable_runWithPriority(
Scheduler.unstable_IdlePriority,
() => setDidMount(true),
),
); );
} }
}, [didMount]); }, [didMount]);

View File

@ -120,3 +120,6 @@ export const enableLegacyFBSupport = false;
// interleaved event. Remove this flag once we have migrated to the // interleaved event. Remove this flag once we have migrated to the
// new behavior. // new behavior.
export const deferRenderPhaseUpdateToNextBatch = true; export const deferRenderPhaseUpdateToNextBatch = true;
// Replacement for runWithPriority in React internals.
export const decoupleUpdatePriorityFromScheduler = false;

View File

@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
export const enableNewReconciler = false; export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true; export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
// Flow magic to verify the exports of this file match the original version. // Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars

View File

@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
export const enableNewReconciler = false; export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true; export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
// Flow magic to verify the exports of this file match the original version. // Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars

View File

@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
export const enableNewReconciler = false; export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true; export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
// Flow magic to verify the exports of this file match the original version. // Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars

View File

@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
export const enableNewReconciler = false; export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true; export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
// Flow magic to verify the exports of this file match the original version. // Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars

View File

@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
export const enableNewReconciler = false; export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true; export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
// Flow magic to verify the exports of this file match the original version. // Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars

View File

@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
export const enableNewReconciler = false; export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true; export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
// Flow magic to verify the exports of this file match the original version. // Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars

View File

@ -18,6 +18,7 @@ export const disableInputAttributeSyncing = __VARIANT__;
export const enableFilterEmptyStringAttributesDOM = __VARIANT__; export const enableFilterEmptyStringAttributesDOM = __VARIANT__;
export const enableLegacyFBSupport = __VARIANT__; export const enableLegacyFBSupport = __VARIANT__;
export const enableDebugTracing = !__VARIANT__; export const enableDebugTracing = !__VARIANT__;
export const decoupleUpdatePriorityFromScheduler = __VARIANT__;
// This only has an effect in the new reconciler. But also, the new reconciler // This only has an effect in the new reconciler. But also, the new reconciler
// is only enabled when __VARIANT__ is true. So this is set to the opposite of // is only enabled when __VARIANT__ is true. So this is set to the opposite of

View File

@ -75,6 +75,7 @@ export const warnUnstableRenderSubtreeIntoContainer = false;
// don't have to add another test dimension. The build system will compile this // don't have to add another test dimension. The build system will compile this
// to the correct value. // to the correct value.
export const enableNewReconciler = __VARIANT__; export const enableNewReconciler = __VARIANT__;
export const decoupleUpdatePriorityFromScheduler = __VARIANT__;
// TODO: This does not currently exist in the new reconciler fork. // TODO: This does not currently exist in the new reconciler fork.
export const enableDebugTracing = !__VARIANT__; export const enableDebugTracing = !__VARIANT__;