Skip to content

Commit b7e6310

Browse files
authored
Stop tracking roots with pending discrete updates (#20978)
Now that discrete updates are flushed synchronously in a microtask, there's no need to track them in their on queue. They're already in the queue we use for all sync work. So we can call that directly.
1 parent 860f673 commit b7e6310

File tree

4 files changed

+34
-190
lines changed

4 files changed

+34
-190
lines changed

packages/react-reconciler/src/ReactFiberLane.new.js

-10
Original file line numberDiff line numberDiff line change
@@ -737,16 +737,6 @@ export function markRootExpired(root: FiberRoot, expiredLanes: Lanes) {
737737
root.expiredLanes |= expiredLanes & root.pendingLanes;
738738
}
739739

740-
export function markDiscreteUpdatesExpired(root: FiberRoot) {
741-
if (root.pendingLanes & InputDiscreteLane) {
742-
root.expiredLanes |= InputDiscreteLane;
743-
}
744-
}
745-
746-
export function hasDiscreteLanes(lanes: Lanes) {
747-
return (lanes & InputDiscreteLane) !== NoLanes;
748-
}
749-
750740
export function markRootMutableRead(root: FiberRoot, updateLane: Lane) {
751741
root.mutableReadLanes |= updateLane & root.pendingLanes;
752742
}

packages/react-reconciler/src/ReactFiberLane.old.js

-10
Original file line numberDiff line numberDiff line change
@@ -737,16 +737,6 @@ export function markRootExpired(root: FiberRoot, expiredLanes: Lanes) {
737737
root.expiredLanes |= expiredLanes & root.pendingLanes;
738738
}
739739

740-
export function markDiscreteUpdatesExpired(root: FiberRoot) {
741-
if (root.pendingLanes & InputDiscreteLane) {
742-
root.expiredLanes |= InputDiscreteLane;
743-
}
744-
}
745-
746-
export function hasDiscreteLanes(lanes: Lanes) {
747-
return (lanes & InputDiscreteLane) !== NoLanes;
748-
}
749-
750740
export function markRootMutableRead(root: FiberRoot, updateLane: Lane) {
751741
root.mutableReadLanes |= updateLane & root.pendingLanes;
752742
}

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

+17-85
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,10 @@ import invariant from 'shared/invariant';
3939
import {
4040
scheduleCallback,
4141
cancelCallback,
42-
getCurrentPriorityLevel,
4342
shouldYield,
4443
requestPaint,
4544
now,
4645
ImmediatePriority as ImmediateSchedulerPriority,
47-
UserBlockingPriority as UserBlockingSchedulerPriority,
4846
NormalPriority as NormalSchedulerPriority,
4947
flushSyncCallbackQueue,
5048
scheduleSyncCallback,
@@ -148,7 +146,6 @@ import {
148146
mergeLanes,
149147
removeLanes,
150148
pickArbitraryLane,
151-
hasDiscreteLanes,
152149
includesNonIdleWork,
153150
includesOnlyRetries,
154151
includesOnlyTransitions,
@@ -163,10 +160,8 @@ import {
163160
markRootSuspended as markRootSuspended_dontCallThisOneDirectly,
164161
markRootPinged,
165162
markRootExpired,
166-
markDiscreteUpdatesExpired,
167163
markRootFinished,
168164
lanePriorityToSchedulerPriority,
169-
higherLanePriority,
170165
} from './ReactFiberLane.new';
171166
import {requestCurrentTransition, NoTransition} from './ReactFiberTransition';
172167
import {beginWork as originalBeginWork} from './ReactFiberBeginWork.new';
@@ -243,14 +238,13 @@ const {
243238

244239
type ExecutionContext = number;
245240

246-
export const NoContext = /* */ 0b0000000;
247-
const BatchedContext = /* */ 0b0000001;
248-
const EventContext = /* */ 0b0000010;
249-
const DiscreteEventContext = /* */ 0b0000100;
250-
const LegacyUnbatchedContext = /* */ 0b0001000;
251-
const RenderContext = /* */ 0b0010000;
252-
const CommitContext = /* */ 0b0100000;
253-
export const RetryAfterError = /* */ 0b1000000;
241+
export const NoContext = /* */ 0b000000;
242+
const BatchedContext = /* */ 0b000001;
243+
const EventContext = /* */ 0b000010;
244+
const LegacyUnbatchedContext = /* */ 0b000100;
245+
const RenderContext = /* */ 0b001000;
246+
const CommitContext = /* */ 0b010000;
247+
export const RetryAfterError = /* */ 0b100000;
254248

255249
type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5;
256250
const RootIncomplete = 0;
@@ -331,8 +325,6 @@ let pendingPassiveEffectsRenderPriority: LanePriority = NoLanePriority;
331325
let pendingPassiveEffectsLanes: Lanes = NoLanes;
332326
let pendingPassiveProfilerEffects: Array<Fiber> = [];
333327

334-
let rootsWithPendingDiscreteUpdates: Set<FiberRoot> | null = null;
335-
336328
// Use these to prevent an infinite loop of nested updates
337329
const NESTED_UPDATE_LIMIT = 50;
338330
let nestedUpdateCount: number = 0;
@@ -434,29 +426,17 @@ export function requestUpdateLane(fiber: Fiber): Lane {
434426
return currentEventTransitionLane;
435427
}
436428

437-
// TODO: Remove this dependency on the Scheduler priority.
438-
// To do that, we're replacing it with an update lane priority.
439-
const schedulerPriority = getCurrentPriorityLevel();
440-
441-
// Find the correct lane based on priorities. Ideally, this would just be
442-
// the update lane priority, but for now we're also checking for discrete
443-
// updates and falling back to the scheduler priority.
444-
let lane;
445-
if (
446-
// TODO: Temporary. We're removing the concept of discrete updates.
447-
(executionContext & DiscreteEventContext) !== NoContext &&
448-
schedulerPriority === UserBlockingSchedulerPriority
449-
) {
450-
lane = findUpdateLane(InputDiscreteLanePriority);
451-
} else if (getCurrentUpdateLanePriority() !== NoLanePriority) {
452-
const currentLanePriority = getCurrentUpdateLanePriority();
453-
lane = findUpdateLane(currentLanePriority);
454-
} else {
455-
const eventLanePriority = getCurrentEventPriority();
456-
lane = findUpdateLane(eventLanePriority);
429+
// Updates originating inside certain React methods, like flushSync, have
430+
// their priority set by tracking it with a context variable.
431+
const updateLanePriority = getCurrentUpdateLanePriority();
432+
if (updateLanePriority !== NoLanePriority) {
433+
return findUpdateLane(updateLanePriority);
457434
}
458435

459-
return lane;
436+
// This update originated outside React. Ask the host environement for an
437+
// appropriate priority, based on the type of event.
438+
const eventLanePriority = getCurrentEventPriority();
439+
return findUpdateLane(eventLanePriority);
460440
}
461441

462442
function requestRetryLane(fiber: Fiber) {
@@ -578,23 +558,6 @@ export function scheduleUpdateOnFiber(
578558
}
579559
}
580560
} else {
581-
const updateLanePriority = getCurrentUpdateLanePriority();
582-
583-
// Schedule a discrete update but only if it's not Sync.
584-
if (
585-
(executionContext & DiscreteEventContext) !== NoContext &&
586-
// Only updates greater than default considered discrete, even inside a discrete event.
587-
higherLanePriority(updateLanePriority, DefaultLanePriority) !==
588-
DefaultLanePriority
589-
) {
590-
// This is the result of a discrete event. Track the lowest priority
591-
// discrete update per root so we can flush them early, if needed.
592-
if (rootsWithPendingDiscreteUpdates === null) {
593-
rootsWithPendingDiscreteUpdates = new Set([root]);
594-
} else {
595-
rootsWithPendingDiscreteUpdates.add(root);
596-
}
597-
}
598561
// Schedule other updates after in case the callback is sync.
599562
ensureRootIsScheduled(root, eventTime);
600563
schedulePendingInteractions(root, lane);
@@ -1096,7 +1059,7 @@ export function flushDiscreteUpdates() {
10961059
// like `el.focus()`. Exit.
10971060
return;
10981061
}
1099-
flushPendingDiscreteUpdates();
1062+
flushSyncCallbackQueue();
11001063
// If the discrete updates scheduled passive effects, flush them now so that
11011064
// they fire before the next serial event.
11021065
flushPassiveEffects();
@@ -1112,21 +1075,6 @@ export function deferredUpdates<A>(fn: () => A): A {
11121075
}
11131076
}
11141077

1115-
function flushPendingDiscreteUpdates() {
1116-
if (rootsWithPendingDiscreteUpdates !== null) {
1117-
// For each root with pending discrete updates, schedule a callback to
1118-
// immediately flush them.
1119-
const roots = rootsWithPendingDiscreteUpdates;
1120-
rootsWithPendingDiscreteUpdates = null;
1121-
roots.forEach(root => {
1122-
markDiscreteUpdatesExpired(root);
1123-
ensureRootIsScheduled(root, now());
1124-
});
1125-
}
1126-
// Now flush the immediate queue.
1127-
flushSyncCallbackQueue();
1128-
}
1129-
11301078
export function batchedUpdates<A, R>(fn: A => R, a: A): R {
11311079
const prevExecutionContext = executionContext;
11321080
executionContext |= BatchedContext;
@@ -1164,16 +1112,12 @@ export function discreteUpdates<A, B, C, D, R>(
11641112
c: C,
11651113
d: D,
11661114
): R {
1167-
const prevExecutionContext = executionContext;
1168-
executionContext |= DiscreteEventContext;
1169-
11701115
const previousLanePriority = getCurrentUpdateLanePriority();
11711116
try {
11721117
setCurrentUpdateLanePriority(InputDiscreteLanePriority);
11731118
return fn(a, b, c, d);
11741119
} finally {
11751120
setCurrentUpdateLanePriority(previousLanePriority);
1176-
executionContext = prevExecutionContext;
11771121
if (executionContext === NoContext) {
11781122
// Flush the immediate callbacks that were scheduled during this batch
11791123
resetRenderTimer();
@@ -1802,18 +1746,6 @@ function commitRootImpl(root, renderPriorityLevel) {
18021746
let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
18031747
markRootFinished(root, remainingLanes);
18041748

1805-
// Clear already finished discrete updates in case that a later call of
1806-
// `flushDiscreteUpdates` starts a useless render pass which may cancels
1807-
// a scheduled timeout.
1808-
if (rootsWithPendingDiscreteUpdates !== null) {
1809-
if (
1810-
!hasDiscreteLanes(remainingLanes) &&
1811-
rootsWithPendingDiscreteUpdates.has(root)
1812-
) {
1813-
rootsWithPendingDiscreteUpdates.delete(root);
1814-
}
1815-
}
1816-
18171749
if (root === workInProgressRoot) {
18181750
// We can reset these now that they are finished.
18191751
workInProgressRoot = null;

0 commit comments

Comments
 (0)