@samitouri / QOS-React / commits / 91a2e8173f

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

Ricky committed Jul 6, 2020 at 18:53 UTC 91a2e8173f1fadd2dfd4b12753ebcdc60986d42d
31 files changed +394 -65
packages/react-dom/index.classic.fb.js
+1
@@ -34,6 +34,7 @@ export {
34 createBlockingRoot as unstable_createBlockingRoot,
35 unstable_flushControlled,
36 unstable_scheduleHydration,
37 + unstable_runWithPriority,
38 unstable_renderSubtreeIntoContainer,
39 unstable_createPortal,
40 unstable_createEventHandle,
packages/react-dom/index.experimental.js
+2
@@ -23,6 +23,8 @@ export {
23 createBlockingRoot as unstable_createBlockingRoot,
24 unstable_flushControlled,
25 unstable_scheduleHydration,
26 + // DO NOT USE: Temporarily exposing this to migrate off of Scheduler.runWithPriority.
27 + unstable_runWithPriority,
28 // Disabled behind disableUnstableRenderSubtreeIntoContainer
29 unstable_renderSubtreeIntoContainer,
30 // Disabled behind disableUnstableCreatePortal
packages/react-dom/index.js
+1
@@ -25,6 +25,7 @@ export {
25 createBlockingRoot as unstable_createBlockingRoot,
26 unstable_flushControlled,
27 unstable_scheduleHydration,
28 + unstable_runWithPriority,
29 unstable_renderSubtreeIntoContainer,
30 unstable_createPortal,
31 unstable_createEventHandle,
packages/react-dom/index.modern.fb.js
+1
@@ -19,6 +19,7 @@ export {
19 createBlockingRoot as unstable_createBlockingRoot,
20 unstable_flushControlled,
21 unstable_scheduleHydration,
22 + unstable_runWithPriority,
23 unstable_createEventHandle,
24 unstable_isNewReconciler,
25 } from './src/client/ReactDOM';
packages/react-dom/src/client/ReactDOM.js
+9
@@ -35,6 +35,8 @@ import {
35 attemptUserBlockingHydration,
36 attemptContinuousHydration,
37 attemptHydrationAtCurrentPriority,
38 + runWithPriority,
39 + getCurrentUpdatePriority,
40 } from 'react-reconciler/src/ReactFiberReconciler';
41 import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
42 import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -58,6 +60,8 @@ import {
60 setAttemptContinuousHydration,
61 setAttemptHydrationAtCurrentPriority,
62 queueExplicitHydrationTarget,
63 + setGetCurrentUpdatePriority,
64 + setAttemptHydrationAtPriority,
65 } from '../events/ReactDOMEventReplaying';
66 import {setBatchingImplementation} from '../events/ReactDOMUpdateBatching';
67 import {
@@ -70,6 +74,8 @@ setAttemptSynchronousHydration(attemptSynchronousHydration);
74 setAttemptUserBlockingHydration(attemptUserBlockingHydration);
75 setAttemptContinuousHydration(attemptContinuousHydration);
76 setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority);
77 +setGetCurrentUpdatePriority(getCurrentUpdatePriority);
78 +setAttemptHydrationAtPriority(runWithPriority);
79
80 let didWarnAboutUnstableCreatePortal = false;
81 let didWarnAboutUnstableRenderSubtreeIntoContainer = false;
@@ -205,6 +211,9 @@ export {
211 unstable_createPortal,
212 // enableCreateEventHandleAPI
213 createEventHandle as unstable_createEventHandle,
214 + // TODO: Remove this once callers migrate to alternatives.
215 + // This should only be used by React internals.
216 + runWithPriority as unstable_runWithPriority,
217 };
218
219 const foundDevTools = injectIntoDevTools({
packages/react-dom/src/events/ReactDOMEventReplaying.js
+32 -6
@@ -12,7 +12,10 @@ import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
12 import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
13 import type {ElementListenerMap} from '../client/ReactDOMComponentTree';
14 import type {EventSystemFlags} from './EventSystemFlags';
15 -import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
15 +import type {
16 + FiberRoot,
17 + ReactPriorityLevel,
18 +} from 'react-reconciler/src/ReactInternalTypes';
19
20 import {
21 enableDeprecatedFlareAPI,
@@ -64,6 +67,23 @@ export function setAttemptHydrationAtCurrentPriority(
67 attemptHydrationAtCurrentPriority = fn;
68 }
69
70 +let getCurrentUpdatePriority: () => ReactPriorityLevel;
71 +
72 +export function setGetCurrentUpdatePriority(fn: () => ReactPriorityLevel) {
73 + getCurrentUpdatePriority = fn;
74 +}
75 +
76 +let attemptHydrationAtPriority: <T>(
77 + priority: ReactPriorityLevel,
78 + fn: () => T,
79 +) => T;
80 +
81 +export function setAttemptHydrationAtPriority(
82 + fn: <T>(priority: ReactPriorityLevel, fn: () => T) => T,
83 +) {
84 + attemptHydrationAtPriority = fn;
85 +}
86 +
87 // TODO: Upgrade this definition once we're on a newer version of Flow that
88 // has this definition built-in.
89 type PointerEvent = Event & {
@@ -147,6 +167,7 @@ type QueuedHydrationTarget = {|
167 blockedOn: null | Container | SuspenseInstance,
168 target: Node,
169 priority: number,
170 + lanePriority: ReactPriorityLevel,
171 |};
172 const queuedExplicitHydrationTargets: Array<QueuedHydrationTarget> = [];
173
@@ -508,9 +529,12 @@ function attemptExplicitHydrationTarget(
529 // We're blocked on hydrating this boundary.
530 // Increase its priority.
531 queuedTarget.blockedOn = instance;
511 - runWithPriority(queuedTarget.priority, () => {
512 - attemptHydrationAtCurrentPriority(nearestMounted);
532 + attemptHydrationAtPriority(queuedTarget.lanePriority, () => {
533 + runWithPriority(queuedTarget.priority, () => {
534 + attemptHydrationAtCurrentPriority(nearestMounted);
535 + });
536 });
537 +
538 return;
539 }
540 } else if (tag === HostRoot) {
@@ -529,15 +553,17 @@ function attemptExplicitHydrationTarget(
553
554 export function queueExplicitHydrationTarget(target: Node): void {
555 if (enableSelectiveHydration) {
532 - const priority = getCurrentPriorityLevel();
556 + const schedulerPriority = getCurrentPriorityLevel();
557 + const updateLanePriority = getCurrentUpdatePriority();
558 const queuedTarget: QueuedHydrationTarget = {
559 blockedOn: null,
560 target: target,
536 - priority: priority,
561 + priority: schedulerPriority,
562 + lanePriority: updateLanePriority,
563 };
564 let i = 0;
565 for (; i < queuedExplicitHydrationTargets.length; i++) {
540 - if (priority <= queuedExplicitHydrationTargets[i].priority) {
566 + if (schedulerPriority <= queuedExplicitHydrationTargets[i].priority) {
567 break;
568 }
569 }
packages/react-dom/src/events/plugins/__tests__/ModernSimpleEventPlugin-test.js
+10 -5
@@ -231,6 +231,8 @@ describe('SimpleEventPlugin', function() {
231 describe('interactive events, in concurrent mode', () => {
232 beforeEach(() => {
233 jest.resetModules();
234 +
235 + React = require('react');
236 ReactDOM = require('react-dom');
237 Scheduler = require('scheduler');
238 });
@@ -377,11 +379,14 @@ describe('SimpleEventPlugin', function() {
379 <button
380 ref={el => (button = el)}
381 onClick={() => {
380 - Scheduler.unstable_next(() => {
381 - this.setState(state => ({
382 - lowPriCount: state.lowPriCount + 1,
383 - }));
384 - });
382 + React.unstable_withSuspenseConfig(
383 + () => {
384 + this.setState(state => ({
385 + lowPriCount: state.lowPriCount + 1,
386 + }));
387 + },
388 + {timeoutMs: 5000},
389 + );
390 }}>
391 {text}
392 </button>
packages/react-noop-renderer/src/ReactNoop.js
+3
@@ -47,6 +47,9 @@ export const {
47 act,
48 dumpTree,
49 getRoot,
50 + // TODO: Remove this once callers migrate to alternatives.
51 + // This should only be used by React internals.
52 + unstable_runWithPriority,
53 } = createReactNoop(
54 ReactFiberReconciler, // reconciler
55 true, // useMutation
packages/react-noop-renderer/src/ReactNoopPersistent.js
+3
@@ -47,6 +47,9 @@ export const {
47 act,
48 dumpTree,
49 getRoot,
50 + // TODO: Remove this once callers migrate to alternatives.
51 + // This should only be used by React internals.
52 + unstable_runWithPriority,
53 } = createReactNoop(
54 ReactFiberReconciler, // reconciler
55 false, // useMutation
packages/react-noop-renderer/src/createReactNoop.js
+2
@@ -954,6 +954,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
954 return Scheduler.unstable_flushExpired();
955 },
956
957 + unstable_runWithPriority: NoopRenderer.runWithPriority,
958 +
959 batchedUpdates: NoopRenderer.batchedUpdates,
960
961 deferredUpdates: NoopRenderer.deferredUpdates,
packages/react-reconciler/src/ReactFiberHooks.new.js
+14
@@ -30,11 +30,16 @@ import {NoMode, BlockingMode} from './ReactTypeOfMode';
30 import {
31 NoLane,
32 NoLanes,
33 + InputContinuousLanePriority,
34 isSubsetOfLanes,
35 mergeLanes,
36 removeLanes,
37 markRootEntangled,
38 markRootMutableRead,
39 + getCurrentUpdateLanePriority,
40 + setCurrentUpdateLanePriority,
41 + higherLanePriority,
42 + DefaultLanePriority,
43 } from './ReactFiberLane';
44 import {readContext} from './ReactFiberNewContext.new';
45 import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.new';
@@ -1498,12 +1503,20 @@ function rerenderDeferredValue<T>(
1503
1504 function startTransition(setPending, config, callback) {
1505 const priorityLevel = getCurrentPriorityLevel();
1506 + const previousLanePriority = getCurrentUpdateLanePriority();
1507 + setCurrentUpdateLanePriority(
1508 + higherLanePriority(previousLanePriority, InputContinuousLanePriority),
1509 + );
1510 runWithPriority(
1511 priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
1512 () => {
1513 setPending(true);
1514 },
1515 );
1516 +
1517 + // If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
1518 + setCurrentUpdateLanePriority(DefaultLanePriority);
1519 +
1520 runWithPriority(
1521 priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
1522 () => {
@@ -1513,6 +1526,7 @@ function startTransition(setPending, config, callback) {
1526 setPending(false);
1527 callback();
1528 } finally {
1529 + setCurrentUpdateLanePriority(previousLanePriority);
1530 ReactCurrentBatchConfig.suspense = previousConfig;
1531 }
1532 },
packages/react-reconciler/src/ReactFiberHooks.old.js
+14
@@ -33,11 +33,16 @@ import {NoMode, BlockingMode, DebugTracingMode} from './ReactTypeOfMode';
33 import {
34 NoLane,
35 NoLanes,
36 + InputContinuousLanePriority,
37 isSubsetOfLanes,
38 mergeLanes,
39 removeLanes,
40 markRootEntangled,
41 markRootMutableRead,
42 + getCurrentUpdateLanePriority,
43 + setCurrentUpdateLanePriority,
44 + higherLanePriority,
45 + DefaultLanePriority,
46 } from './ReactFiberLane';
47 import {readContext} from './ReactFiberNewContext.old';
48 import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.old';
@@ -1502,12 +1507,20 @@ function rerenderDeferredValue<T>(
1507
1508 function startTransition(setPending, config, callback) {
1509 const priorityLevel = getCurrentPriorityLevel();
1510 + const previousLanePriority = getCurrentUpdateLanePriority();
1511 + setCurrentUpdateLanePriority(
1512 + higherLanePriority(previousLanePriority, InputContinuousLanePriority),
1513 + );
1514 runWithPriority(
1515 priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
1516 () => {
1517 setPending(true);
1518 },
1519 );
1520 +
1521 + // If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
1522 + setCurrentUpdateLanePriority(DefaultLanePriority);
1523 +
1524 runWithPriority(
1525 priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
1526 () => {
@@ -1517,6 +1530,7 @@ function startTransition(setPending, config, callback) {
1530 setPending(false);
1531 callback();
1532 } finally {
1533 + setCurrentUpdateLanePriority(previousLanePriority);
1534 ReactCurrentBatchConfig.suspense = previousConfig;
1535 }
1536 },
packages/react-reconciler/src/ReactFiberLane.js
+19 -2
@@ -49,10 +49,10 @@ const InputDiscreteHydrationLanePriority: LanePriority = 14;
49 export const InputDiscreteLanePriority: LanePriority = 13;
50
51 const InputContinuousHydrationLanePriority: LanePriority = 12;
52 -const InputContinuousLanePriority: LanePriority = 11;
52 +export const InputContinuousLanePriority: LanePriority = 11;
53
54 const DefaultHydrationLanePriority: LanePriority = 10;
55 -const DefaultLanePriority: LanePriority = 9;
55 +export const DefaultLanePriority: LanePriority = 9;
56
57 const TransitionShortHydrationLanePriority: LanePriority = 8;
58 export const TransitionShortLanePriority: LanePriority = 7;
@@ -120,6 +120,16 @@ export const OffscreenLane: Lane = /* */ 0b1000000000000000000
120
121 export const NoTimestamp = -1;
122
123 +let currentUpdateLanePriority: LanePriority = NoLanePriority;
124 +
125 +export function getCurrentUpdateLanePriority(): LanePriority {
126 + return currentUpdateLanePriority;
127 +}
128 +
129 +export function setCurrentUpdateLanePriority(newLanePriority: LanePriority) {
130 + currentUpdateLanePriority = newLanePriority;
131 +}
132 +
133 // "Registers" used to "return" multiple values
134 // Used by getHighestPriorityLanes and getNextLanes:
135 let return_highestLanePriority: LanePriority = DefaultLanePriority;
@@ -651,6 +661,13 @@ export function higherPriorityLane(a: Lane, b: Lane) {
661 return a !== NoLane && a < b ? a : b;
662 }
663
664 +export function higherLanePriority(
665 + a: LanePriority,
666 + b: LanePriority,
667 +): LanePriority {
668 + return a !== NoLanePriority && a > b ? a : b;
669 +}
670 +
671 export function createLaneMap<T>(initial: T): LaneMap<T> {
672 return new Array(TotalLanes).fill(initial);
673 }
packages/react-reconciler/src/ReactFiberReconciler.js
+10
@@ -50,6 +50,8 @@ import {
50 focusWithin as focusWithin_old,
51 observeVisibleRects as observeVisibleRects_old,
52 registerMutableSourceForHydration as registerMutableSourceForHydration_old,
53 + runWithPriority as runWithPriority_old,
54 + getCurrentUpdatePriority as getCurrentUpdatePriority_old,
55 } from './ReactFiberReconciler.old';
56
57 import {
@@ -88,6 +90,8 @@ import {
90 focusWithin as focusWithin_new,
91 observeVisibleRects as observeVisibleRects_new,
92 registerMutableSourceForHydration as registerMutableSourceForHydration_new,
93 + runWithPriority as runWithPriority_new,
94 + getCurrentUpdatePriority as getCurrentUpdatePriority_new,
95 } from './ReactFiberReconciler.new';
96
97 export const createContainer = enableNewReconciler
@@ -139,6 +143,9 @@ export const attemptContinuousHydration = enableNewReconciler
143 export const attemptHydrationAtCurrentPriority = enableNewReconciler
144 ? attemptHydrationAtCurrentPriority_new
145 : attemptHydrationAtCurrentPriority_old;
146 +export const getCurrentUpdatePriority = enableNewReconciler
147 + ? getCurrentUpdatePriority_new
148 + : getCurrentUpdatePriority_old;
149 export const findHostInstance = enableNewReconciler
150 ? findHostInstance_new
151 : findHostInstance_old;
@@ -194,3 +201,6 @@ export const observeVisibleRects = enableNewReconciler
201 export const registerMutableSourceForHydration = enableNewReconciler
202 ? registerMutableSourceForHydration_new
203 : registerMutableSourceForHydration_old;
204 +export const runWithPriority = enableNewReconciler
205 + ? runWithPriority_new
206 + : runWithPriority_old;
packages/react-reconciler/src/ReactFiberReconciler.new.js
+23 -1
@@ -7,7 +7,11 @@
7 * @flow
8 */
9
10 -import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes';
10 +import type {
11 + Fiber,
12 + ReactPriorityLevel,
13 + SuspenseHydrationCallbacks,
14 +} from './ReactInternalTypes';
15 import type {FiberRoot} from './ReactInternalTypes';
16 import type {RootTag} from './ReactRootTags';
17 import type {
@@ -79,6 +83,10 @@ import {
83 NoTimestamp,
84 getHighestPriorityPendingLanes,
85 higherPriorityLane,
86 + getCurrentUpdateLanePriority,
87 + setCurrentUpdateLanePriority,
88 + schedulerPriorityToLanePriority,
89 + lanePriorityToSchedulerPriority,
90 } from './ReactFiberLane';
91 import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig';
92 import {
@@ -424,6 +432,20 @@ export function attemptHydrationAtCurrentPriority(fiber: Fiber): void {
432 markRetryLaneIfNotHydrated(fiber, lane);
433 }
434
435 +export function runWithPriority<T>(priority: ReactPriorityLevel, fn: () => T) {
436 + const previousPriority = getCurrentUpdateLanePriority();
437 + try {
438 + setCurrentUpdateLanePriority(schedulerPriorityToLanePriority(priority));
439 + return fn();
440 + } finally {
441 + setCurrentUpdateLanePriority(previousPriority);
442 + }
443 +}
444 +
445 +export function getCurrentUpdatePriority(): ReactPriorityLevel {
446 + return lanePriorityToSchedulerPriority(getCurrentUpdateLanePriority());
447 +}
448 +
449 export {findHostInstance};
450
451 export {findHostInstanceWithWarning};
packages/react-reconciler/src/ReactFiberReconciler.old.js
+23 -1
@@ -7,7 +7,11 @@
7 * @flow
8 */
9
10 -import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes';
10 +import type {
11 + Fiber,
12 + ReactPriorityLevel,
13 + SuspenseHydrationCallbacks,
14 +} from './ReactInternalTypes';
15 import type {FiberRoot} from './ReactInternalTypes';
16 import type {RootTag} from './ReactRootTags';
17 import type {
@@ -79,6 +83,10 @@ import {
83 NoTimestamp,
84 getHighestPriorityPendingLanes,
85 higherPriorityLane,
86 + getCurrentUpdateLanePriority,
87 + setCurrentUpdateLanePriority,
88 + schedulerPriorityToLanePriority,
89 + lanePriorityToSchedulerPriority,
90 } from './ReactFiberLane';
91 import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig';
92 import {
@@ -424,6 +432,20 @@ export function attemptHydrationAtCurrentPriority(fiber: Fiber): void {
432 markRetryLaneIfNotHydrated(fiber, lane);
433 }
434
435 +export function runWithPriority<T>(priority: ReactPriorityLevel, fn: () => T) {
436 + const previousPriority = getCurrentUpdateLanePriority();
437 + try {
438 + setCurrentUpdateLanePriority(schedulerPriorityToLanePriority(priority));
439 + return fn();
440 + } finally {
441 + setCurrentUpdateLanePriority(previousPriority);
442 + }
443 +}
444 +
445 +export function getCurrentUpdatePriority(): ReactPriorityLevel {
446 + return lanePriorityToSchedulerPriority(getCurrentUpdateLanePriority());
447 +}
448 +
449 export {findHostInstance};
450
451 export {findHostInstanceWithWarning};
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+78 -16
@@ -26,6 +26,7 @@ import {
26 enableSchedulerTracing,
27 warnAboutUnmockedScheduler,
28 deferRenderPhaseUpdateToNextBatch,
29 + decoupleUpdatePriorityFromScheduler,
30 } from 'shared/ReactFeatureFlags';
31 import ReactSharedInternals from 'shared/ReactSharedInternals';
32 import invariant from 'shared/invariant';
@@ -113,6 +114,7 @@ import {
114 InputDiscreteLanePriority,
115 TransitionShortLanePriority,
116 TransitionLongLanePriority,
117 + DefaultLanePriority,
118 NoLanes,
119 NoLane,
120 SyncLane,
@@ -130,6 +132,8 @@ import {
132 hasUpdatePriority,
133 getNextLanes,
134 returnNextLanesPriority,
135 + setCurrentUpdateLanePriority,
136 + getCurrentUpdateLanePriority,
137 markStarvedLanesAsExpired,
138 getLanesToRetrySynchronouslyOnError,
139 markRootUpdated,
@@ -394,7 +398,6 @@ export function requestUpdateLane(
398 currentEventWipLanes = workInProgressRootIncludedLanes;
399 }
400
397 - let lane;
401 if (suspenseConfig !== null) {
402 // Use the size of the timeout as a heuristic to prioritize shorter
403 // transitions over longer ones.
@@ -412,26 +415,56 @@ export function requestUpdateLane(
415 : NoLanes;
416 }
417
415 - lane = findTransitionLane(
418 + return findTransitionLane(
419 transitionLanePriority,
420 currentEventWipLanes,
421 currentEventPendingLanes,
422 );
423 + }
424 +
425 + // TODO: Remove this dependency on the Scheduler priority.
426 + // To do that, we're replacing it with an update lane priority.
427 + const schedulerPriority = getCurrentPriorityLevel();
428 +
429 + // The old behavior was using the priority level of the Scheduler.
430 + // This couples React to the Scheduler internals, so we're replacing it
431 + // with the currentUpdateLanePriority above. As an example of how this
432 + // could be problematic, if we're not inside `Scheduler.runWithPriority`,
433 + // then we'll get the priority of the current running Scheduler task,
434 + // which is probably not what we want.
435 + let lane;
436 + if (
437 + // TODO: Temporary. We're removing the concept of discrete updates.
438 + (executionContext & DiscreteEventContext) !== NoContext &&
439 + schedulerPriority === UserBlockingSchedulerPriority
440 + ) {
441 + lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
442 } else {
421 - // TODO: If we're not inside `runWithPriority`, this returns the priority
422 - // of the currently running task. That's probably not what we want.
423 - const schedulerPriority = getCurrentPriorityLevel();
443 + const schedulerLanePriority = schedulerPriorityToLanePriority(
444 + schedulerPriority,
445 + );
446
425 - if (
426 - // TODO: Temporary. We're removing the concept of discrete updates.
427 - (executionContext & DiscreteEventContext) !== NoContext &&
428 - schedulerPriority === UserBlockingSchedulerPriority
429 - ) {
430 - lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
431 - } else {
432 - const lanePriority = schedulerPriorityToLanePriority(schedulerPriority);
433 - lane = findUpdateLane(lanePriority, currentEventWipLanes);
447 + if (decoupleUpdatePriorityFromScheduler) {
448 + // In the new strategy, we will track the current update lane priority
449 + // inside React and use that priority to select a lane for this update.
450 + // For now, we're just logging when they're different so we can assess.
451 + const currentUpdateLanePriority = getCurrentUpdateLanePriority();
452 +
453 + if (
454 + schedulerLanePriority !== currentUpdateLanePriority &&
455 + currentUpdateLanePriority !== NoLanePriority
456 + ) {
457 + if (__DEV__) {
458 + console.error(
459 + 'Expected current scheduler lane priority %s to match current update lane priority %s',
460 + schedulerLanePriority,
461 + currentUpdateLanePriority,
462 + );
463 + }
464 + }
465 }
466 +
467 + lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
468 }
469
470 return lane;
@@ -1068,7 +1101,13 @@ export function flushDiscreteUpdates() {
1101
1102 export function deferredUpdates<A>(fn: () => A): A {
1103 // TODO: Remove in favor of Scheduler.next
1071 - return runWithPriority(NormalSchedulerPriority, fn);
1104 + const previousLanePriority = getCurrentUpdateLanePriority();
1105 + try {
1106 + setCurrentUpdateLanePriority(DefaultLanePriority);
1107 + return runWithPriority(NormalSchedulerPriority, fn);
1108 + } finally {
1109 + setCurrentUpdateLanePriority(previousLanePriority);
1110 + }
1111 }
1112
1113 function flushPendingDiscreteUpdates() {
@@ -1123,13 +1162,16 @@ export function discreteUpdates<A, B, C, D, R>(
1162 ): R {
1163 const prevExecutionContext = executionContext;
1164 executionContext |= DiscreteEventContext;
1165 + const previousLanePriority = getCurrentUpdateLanePriority();
1166 try {
1167 + setCurrentUpdateLanePriority(InputDiscreteLanePriority);
1168 // Should this
1169 return runWithPriority(
1170 UserBlockingSchedulerPriority,
1171 fn.bind(null, a, b, c, d),
1172 );
1173 } finally {
1174 + setCurrentUpdateLanePriority(previousLanePriority);
1175 executionContext = prevExecutionContext;
1176 if (executionContext === NoContext) {
1177 // 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 {
1208 return fn(a);
1209 }
1210 executionContext |= BatchedContext;
1211 + const previousLanePriority = getCurrentUpdateLanePriority();
1212 try {
1213 + setCurrentUpdateLanePriority(SyncLanePriority);
1214 if (fn) {
1215 return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
1216 } else {
1217 return (undefined: $FlowFixMe);
1218 }
1219 } finally {
1220 + setCurrentUpdateLanePriority(previousLanePriority);
1221 executionContext = prevExecutionContext;
1222 // Flush the immediate callbacks that were scheduled during this batch.
1223 // 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 {
1229 export function flushControlled(fn: () => mixed): void {
1230 const prevExecutionContext = executionContext;
1231 executionContext |= BatchedContext;
1232 + const previousLanePriority = getCurrentUpdateLanePriority();
1233 try {
1234 + setCurrentUpdateLanePriority(SyncLanePriority);
1235 runWithPriority(ImmediateSchedulerPriority, fn);
1236 } finally {
1237 + setCurrentUpdateLanePriority(previousLanePriority);
1238 executionContext = prevExecutionContext;
1239 if (executionContext === NoContext) {
1240 // Flush the immediate callbacks that were scheduled during this batch
@@ -1867,6 +1915,9 @@ function commitRootImpl(root, renderPriorityLevel) {
1915 }
1916
1917 if (firstEffect !== null) {
1918 + const previousLanePriority = getCurrentUpdateLanePriority();
1919 + setCurrentUpdateLanePriority(SyncLanePriority);
1920 +
1921 const prevExecutionContext = executionContext;
1922 executionContext |= CommitContext;
1923 const prevInteractions = pushInteractions(root);
@@ -1987,6 +2038,9 @@ function commitRootImpl(root, renderPriorityLevel) {
2038 popInteractions(((prevInteractions: any): Set<Interaction>));
2039 }
2040 executionContext = prevExecutionContext;
2041 +
2042 + // Reset the priority to the previous non-sync value.
2043 + setCurrentUpdateLanePriority(previousLanePriority);
2044 } else {
2045 // No effects.
2046 root.current = finishedWork;
@@ -2249,7 +2303,15 @@ export function flushPassiveEffects() {
2303 ? NormalSchedulerPriority
2304 : pendingPassiveEffectsRenderPriority;
2305 pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
2252 - return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
2306 + const previousLanePriority = getCurrentUpdateLanePriority();
2307 + try {
2308 + setCurrentUpdateLanePriority(
2309 + schedulerPriorityToLanePriority(priorityLevel),
2310 + );
2311 + return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
2312 + } finally {
2313 + setCurrentUpdateLanePriority(previousLanePriority);
2314 + }
2315 }
2316 }
2317
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+78 -16
@@ -26,6 +26,7 @@ import {
26 enableSchedulerTracing,
27 warnAboutUnmockedScheduler,
28 deferRenderPhaseUpdateToNextBatch,
29 + decoupleUpdatePriorityFromScheduler,
30 enableDebugTracing,
31 } from 'shared/ReactFeatureFlags';
32 import ReactSharedInternals from 'shared/ReactSharedInternals';
@@ -124,6 +125,7 @@ import {
125 InputDiscreteLanePriority,
126 TransitionShortLanePriority,
127 TransitionLongLanePriority,
128 + DefaultLanePriority,
129 NoLanes,
130 NoLane,
131 SyncLane,
@@ -141,6 +143,8 @@ import {
143 hasUpdatePriority,
144 getNextLanes,
145 returnNextLanesPriority,
146 + setCurrentUpdateLanePriority,
147 + getCurrentUpdateLanePriority,
148 markStarvedLanesAsExpired,
149 getLanesToRetrySynchronouslyOnError,
150 markRootUpdated,
@@ -405,7 +409,6 @@ export function requestUpdateLane(
409 currentEventWipLanes = workInProgressRootIncludedLanes;
410 }
411
408 - let lane;
412 if (suspenseConfig !== null) {
413 // Use the size of the timeout as a heuristic to prioritize shorter
414 // transitions over longer ones.
@@ -423,26 +426,56 @@ export function requestUpdateLane(
426 : NoLanes;
427 }
428
426 - lane = findTransitionLane(
429 + return findTransitionLane(
430 transitionLanePriority,
431 currentEventWipLanes,
432 currentEventPendingLanes,
433 );
434 + }
435 +
436 + // TODO: Remove this dependency on the Scheduler priority.
437 + // To do that, we're replacing it with an update lane priority.
438 + const schedulerPriority = getCurrentPriorityLevel();
439 +
440 + // The old behavior was using the priority level of the Scheduler.
441 + // This couples React to the Scheduler internals, so we're replacing it
442 + // with the currentUpdateLanePriority above. As an example of how this
443 + // could be problematic, if we're not inside `Scheduler.runWithPriority`,
444 + // then we'll get the priority of the current running Scheduler task,
445 + // which is probably not what we want.
446 + let lane;
447 + if (
448 + // TODO: Temporary. We're removing the concept of discrete updates.
449 + (executionContext & DiscreteEventContext) !== NoContext &&
450 + schedulerPriority === UserBlockingSchedulerPriority
451 + ) {
452 + lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
453 } else {
432 - // TODO: If we're not inside `runWithPriority`, this returns the priority
433 - // of the currently running task. That's probably not what we want.
434 - const schedulerPriority = getCurrentPriorityLevel();
454 + const schedulerLanePriority = schedulerPriorityToLanePriority(
455 + schedulerPriority,
456 + );
457
436 - if (
437 - // TODO: Temporary. We're removing the concept of discrete updates.
438 - (executionContext & DiscreteEventContext) !== NoContext &&
439 - schedulerPriority === UserBlockingSchedulerPriority
440 - ) {
441 - lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
442 - } else {
443 - const lanePriority = schedulerPriorityToLanePriority(schedulerPriority);
444 - lane = findUpdateLane(lanePriority, currentEventWipLanes);
458 + if (decoupleUpdatePriorityFromScheduler) {
459 + // In the new strategy, we will track the current update lane priority
460 + // inside React and use that priority to select a lane for this update.
461 + // For now, we're just logging when they're different so we can assess.
462 + const currentUpdateLanePriority = getCurrentUpdateLanePriority();
463 +
464 + if (
465 + schedulerLanePriority !== currentUpdateLanePriority &&
466 + currentUpdateLanePriority !== NoLanePriority
467 + ) {
468 + if (__DEV__) {
469 + console.error(
470 + 'Expected current scheduler lane priority %s to match current update lane priority %s',
471 + schedulerLanePriority,
472 + currentUpdateLanePriority,
473 + );
474 + }
475 + }
476 }
477 +
478 + lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
479 }
480
481 return lane;
@@ -1079,7 +1112,13 @@ export function flushDiscreteUpdates() {
1112
1113 export function deferredUpdates<A>(fn: () => A): A {
1114 // TODO: Remove in favor of Scheduler.next
1082 - return runWithPriority(NormalSchedulerPriority, fn);
1115 + const previousLanePriority = getCurrentUpdateLanePriority();
1116 + try {
1117 + setCurrentUpdateLanePriority(DefaultLanePriority);
1118 + return runWithPriority(NormalSchedulerPriority, fn);
1119 + } finally {
1120 + setCurrentUpdateLanePriority(previousLanePriority);
1121 + }
1122 }
1123
1124 function flushPendingDiscreteUpdates() {
@@ -1134,13 +1173,16 @@ export function discreteUpdates<A, B, C, D, R>(
1173 ): R {
1174 const prevExecutionContext = executionContext;
1175 executionContext |= DiscreteEventContext;
1176 + const previousLanePriority = getCurrentUpdateLanePriority();
1177 try {
1178 + setCurrentUpdateLanePriority(InputDiscreteLanePriority);
1179 // Should this
1180 return runWithPriority(
1181 UserBlockingSchedulerPriority,
1182 fn.bind(null, a, b, c, d),
1183 );
1184 } finally {
1185 + setCurrentUpdateLanePriority(previousLanePriority);
1186 executionContext = prevExecutionContext;
1187 if (executionContext === NoContext) {
1188 // 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 {
1219 return fn(a);
1220 }
1221 executionContext |= BatchedContext;
1222 + const previousLanePriority = getCurrentUpdateLanePriority();
1223 try {
1224 + setCurrentUpdateLanePriority(SyncLanePriority);
1225 if (fn) {
1226 return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));
1227 } else {
1228 return (undefined: $FlowFixMe);
1229 }
1230 } finally {
1231 + setCurrentUpdateLanePriority(previousLanePriority);
1232 executionContext = prevExecutionContext;
1233 // Flush the immediate callbacks that were scheduled during this batch.
1234 // 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 {
1240 export function flushControlled(fn: () => mixed): void {
1241 const prevExecutionContext = executionContext;
1242 executionContext |= BatchedContext;
1243 + const previousLanePriority = getCurrentUpdateLanePriority();
1244 try {
1245 + setCurrentUpdateLanePriority(SyncLanePriority);
1246 runWithPriority(ImmediateSchedulerPriority, fn);
1247 } finally {
1248 + setCurrentUpdateLanePriority(previousLanePriority);
1249 executionContext = prevExecutionContext;
1250 if (executionContext === NoContext) {
1251 // Flush the immediate callbacks that were scheduled during this batch
@@ -1915,6 +1963,9 @@ function commitRootImpl(root, renderPriorityLevel) {
1963 }
1964
1965 if (firstEffect !== null) {
1966 + const previousLanePriority = getCurrentUpdateLanePriority();
1967 + setCurrentUpdateLanePriority(SyncLanePriority);
1968 +
1969 const prevExecutionContext = executionContext;
1970 executionContext |= CommitContext;
1971 const prevInteractions = pushInteractions(root);
@@ -2035,6 +2086,9 @@ function commitRootImpl(root, renderPriorityLevel) {
2086 popInteractions(((prevInteractions: any): Set<Interaction>));
2087 }
2088 executionContext = prevExecutionContext;
2089 +
2090 + // Reset the priority to the previous non-sync value.
2091 + setCurrentUpdateLanePriority(previousLanePriority);
2092 } else {
2093 // No effects.
2094 root.current = finishedWork;
@@ -2321,7 +2375,15 @@ export function flushPassiveEffects() {
2375 ? NormalSchedulerPriority
2376 : pendingPassiveEffectsRenderPriority;
2377 pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
2324 - return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
2378 + const previousLanePriority = getCurrentUpdateLanePriority();
2379 + try {
2380 + setCurrentUpdateLanePriority(
2381 + schedulerPriorityToLanePriority(priorityLevel),
2382 + );
2383 + return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
2384 + } finally {
2385 + setCurrentUpdateLanePriority(previousLanePriority);
2386 + }
2387 }
2388 }
2389
packages/react-reconciler/src/SchedulerWithReactIntegration.new.js
+8
@@ -15,6 +15,11 @@ import * as Scheduler from 'scheduler';
15 import {__interactionsRef} from 'scheduler/tracing';
16 import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
17 import invariant from 'shared/invariant';
18 +import {
19 + SyncLanePriority,
20 + getCurrentUpdateLanePriority,
21 + setCurrentUpdateLanePriority,
22 +} from './ReactFiberLane';
23
24 const {
25 unstable_runWithPriority: Scheduler_runWithPriority,
@@ -171,9 +176,11 @@ function flushSyncCallbackQueueImpl() {
176 // Prevent re-entrancy.
177 isFlushingSyncQueue = true;
178 let i = 0;
179 + const previousLanePriority = getCurrentUpdateLanePriority();
180 try {
181 const isSync = true;
182 const queue = syncQueue;
183 + setCurrentUpdateLanePriority(SyncLanePriority);
184 runWithPriority(ImmediatePriority, () => {
185 for (; i < queue.length; i++) {
186 let callback = queue[i];
@@ -195,6 +202,7 @@ function flushSyncCallbackQueueImpl() {
202 );
203 throw error;
204 } finally {
205 + setCurrentUpdateLanePriority(previousLanePriority);
206 isFlushingSyncQueue = false;
207 }
208 }
packages/react-reconciler/src/SchedulerWithReactIntegration.old.js
+8
@@ -15,6 +15,11 @@ import * as Scheduler from 'scheduler';
15 import {__interactionsRef} from 'scheduler/tracing';
16 import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
17 import invariant from 'shared/invariant';
18 +import {
19 + SyncLanePriority,
20 + getCurrentUpdateLanePriority,
21 + setCurrentUpdateLanePriority,
22 +} from './ReactFiberLane';
23
24 const {
25 unstable_runWithPriority: Scheduler_runWithPriority,
@@ -171,9 +176,11 @@ function flushSyncCallbackQueueImpl() {
176 // Prevent re-entrancy.
177 isFlushingSyncQueue = true;
178 let i = 0;
179 + const previousLanePriority = getCurrentUpdateLanePriority();
180 try {
181 const isSync = true;
182 const queue = syncQueue;
183 + setCurrentUpdateLanePriority(SyncLanePriority);
184 runWithPriority(ImmediatePriority, () => {
185 for (; i < queue.length; i++) {
186 let callback = queue[i];
@@ -195,6 +202,7 @@ function flushSyncCallbackQueueImpl() {
202 );
203 throw error;
204 } finally {
205 + setCurrentUpdateLanePriority(previousLanePriority);
206 isFlushingSyncQueue = false;
207 }
208 }
packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js
+37 -16
@@ -516,11 +516,16 @@ describe('ReactIncrementalUpdates', () => {
516 Scheduler.unstable_yieldValue('Committed: ' + log);
517 if (log === 'B') {
518 // Right after B commits, schedule additional updates.
519 - Scheduler.unstable_runWithPriority(
519 + // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
520 + ReactNoop.unstable_runWithPriority(
521 Scheduler.unstable_UserBlockingPriority,
521 - () => {
522 - pushToLog('C');
523 - },
522 + () =>
523 + Scheduler.unstable_runWithPriority(
524 + Scheduler.unstable_UserBlockingPriority,
525 + () => {
526 + pushToLog('C');
527 + },
528 + ),
529 );
530 setLog(prevLog => prevLog + 'D');
531 }
@@ -538,11 +543,17 @@ describe('ReactIncrementalUpdates', () => {
543
544 await ReactNoop.act(async () => {
545 pushToLog('A');
541 - Scheduler.unstable_runWithPriority(
546 +
547 + // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
548 + ReactNoop.unstable_runWithPriority(
549 Scheduler.unstable_UserBlockingPriority,
543 - () => {
544 - pushToLog('B');
545 - },
550 + () =>
551 + Scheduler.unstable_runWithPriority(
552 + Scheduler.unstable_UserBlockingPriority,
553 + () => {
554 + pushToLog('B');
555 + },
556 + ),
557 );
558 });
559 expect(Scheduler).toHaveYielded([
@@ -574,11 +585,16 @@ describe('ReactIncrementalUpdates', () => {
585 Scheduler.unstable_yieldValue('Committed: ' + this.state.log);
586 if (this.state.log === 'B') {
587 // Right after B commits, schedule additional updates.
577 - Scheduler.unstable_runWithPriority(
588 + // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
589 + ReactNoop.unstable_runWithPriority(
590 Scheduler.unstable_UserBlockingPriority,
579 - () => {
580 - this.pushToLog('C');
581 - },
591 + () =>
592 + Scheduler.unstable_runWithPriority(
593 + Scheduler.unstable_UserBlockingPriority,
594 + () => {
595 + this.pushToLog('C');
596 + },
597 + ),
598 );
599 this.pushToLog('D');
600 }
@@ -598,11 +614,16 @@ describe('ReactIncrementalUpdates', () => {
614
615 await ReactNoop.act(async () => {
616 pushToLog('A');
601 - Scheduler.unstable_runWithPriority(
617 + // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
618 + ReactNoop.unstable_runWithPriority(
619 Scheduler.unstable_UserBlockingPriority,
603 - () => {
604 - pushToLog('B');
605 - },
620 + () =>
621 + Scheduler.unstable_runWithPriority(
622 + Scheduler.unstable_UserBlockingPriority,
623 + () => {
624 + pushToLog('B');
625 + },
626 + ),
627 );
628 });
629 expect(Scheduler).toHaveYielded([
packages/react/src/__tests__/ReactDOMTracing-test.internal.js
+7 -2
@@ -232,9 +232,14 @@ describe('ReactDOMTracing', () => {
232 Scheduler.unstable_yieldValue('Child:update');
233 } else {
234 Scheduler.unstable_yieldValue('Child:mount');
235 - Scheduler.unstable_runWithPriority(
235 + // TODO: Double wrapping is temporary while we remove Scheduler runWithPriority.
236 + ReactDOM.unstable_runWithPriority(
237 Scheduler.unstable_IdlePriority,
237 - () => setDidMount(true),
238 + () =>
239 + Scheduler.unstable_runWithPriority(
240 + Scheduler.unstable_IdlePriority,
241 + () => setDidMount(true),
242 + ),
243 );
244 }
245 }, [didMount]);
packages/shared/ReactFeatureFlags.js
+3
@@ -120,3 +120,6 @@ export const enableLegacyFBSupport = false;
120 // interleaved event. Remove this flag once we have migrated to the
121 // new behavior.
122 export const deferRenderPhaseUpdateToNextBatch = true;
123 +
124 +// Replacement for runWithPriority in React internals.
125 +export const decoupleUpdatePriorityFromScheduler = false;
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1
@@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
46
47 export const enableNewReconciler = false;
48 export const deferRenderPhaseUpdateToNextBatch = true;
49 +export const decoupleUpdatePriorityFromScheduler = false;
50
51 // Flow magic to verify the exports of this file match the original version.
52 // eslint-disable-next-line no-unused-vars
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1
@@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
45
46 export const enableNewReconciler = false;
47 export const deferRenderPhaseUpdateToNextBatch = true;
48 +export const decoupleUpdatePriorityFromScheduler = false;
49
50 // Flow magic to verify the exports of this file match the original version.
51 // eslint-disable-next-line no-unused-vars
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
@@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
45
46 export const enableNewReconciler = false;
47 export const deferRenderPhaseUpdateToNextBatch = true;
48 +export const decoupleUpdatePriorityFromScheduler = false;
49
50 // Flow magic to verify the exports of this file match the original version.
51 // eslint-disable-next-line no-unused-vars
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1
@@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
45
46 export const enableNewReconciler = false;
47 export const deferRenderPhaseUpdateToNextBatch = true;
48 +export const decoupleUpdatePriorityFromScheduler = false;
49
50 // Flow magic to verify the exports of this file match the original version.
51 // eslint-disable-next-line no-unused-vars
packages/shared/forks/ReactFeatureFlags.testing.js
+1
@@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
45
46 export const enableNewReconciler = false;
47 export const deferRenderPhaseUpdateToNextBatch = true;
48 +export const decoupleUpdatePriorityFromScheduler = false;
49
50 // Flow magic to verify the exports of this file match the original version.
51 // eslint-disable-next-line no-unused-vars
packages/shared/forks/ReactFeatureFlags.testing.www.js
+1
@@ -45,6 +45,7 @@ export const enableFilterEmptyStringAttributesDOM = false;
45
46 export const enableNewReconciler = false;
47 export const deferRenderPhaseUpdateToNextBatch = true;
48 +export const decoupleUpdatePriorityFromScheduler = false;
49
50 // Flow magic to verify the exports of this file match the original version.
51 // eslint-disable-next-line no-unused-vars
packages/shared/forks/ReactFeatureFlags.www-dynamic.js
+1
@@ -18,6 +18,7 @@ export const disableInputAttributeSyncing = __VARIANT__;
18 export const enableFilterEmptyStringAttributesDOM = __VARIANT__;
19 export const enableLegacyFBSupport = __VARIANT__;
20 export const enableDebugTracing = !__VARIANT__;
21 +export const decoupleUpdatePriorityFromScheduler = __VARIANT__;
22
23 // This only has an effect in the new reconciler. But also, the new reconciler
24 // is only enabled when __VARIANT__ is true. So this is set to the opposite of
packages/shared/forks/ReactFeatureFlags.www.js
+1
@@ -75,6 +75,7 @@ export const warnUnstableRenderSubtreeIntoContainer = false;
75 // don't have to add another test dimension. The build system will compile this
76 // to the correct value.
77 export const enableNewReconciler = __VARIANT__;
78 +export const decoupleUpdatePriorityFromScheduler = __VARIANT__;
79
80 // TODO: This does not currently exist in the new reconciler fork.
81 export const enableDebugTracing = !__VARIANT__;