Skip to content

Commit 79d0531

Browse files
committed
Queue discrete events in microtask
1 parent 5d50687 commit 79d0531

17 files changed

+57
-9
lines changed

packages/react-dom/src/client/ReactDOMHostConfig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ export const queueMicrotask: any =
392392
Promise.resolve(null)
393393
.then(callback)
394394
.catch(handleErrorInNextTick)
395-
: scheduleTimeout;
395+
: scheduleTimeout; // TODO: Determine the best fallback here.
396396

397397
function handleErrorInNextTick(error) {
398398
setTimeout(() => {

packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,15 @@ describe('ChangeEventPlugin', () => {
730730

731731
// Flush callbacks.
732732
// Now the click update has flushed.
733-
expect(Scheduler).toFlushAndYield(['render: ']);
734-
expect(input.value).toBe('');
733+
if (gate(flags => flags.enableDiscreteEventMicroTasks)) {
734+
// Flush microtask queue.
735+
await null;
736+
expect(Scheduler).toHaveYielded(['render: ']);
737+
expect(input.value).toBe('');
738+
} else {
739+
expect(Scheduler).toFlushAndYield(['render: ']);
740+
expect(input.value).toBe('');
741+
}
735742
});
736743

737744
// @gate experimental

packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,11 +470,24 @@ describe('SimpleEventPlugin', function() {
470470
'High-pri count: 7, Low-pri count: 0',
471471
]);
472472

473-
// At the end, both counters should equal the total number of clicks
474-
expect(Scheduler).toFlushAndYield([
475-
'High-pri count: 8, Low-pri count: 0',
476-
'High-pri count: 8, Low-pri count: 8',
477-
]);
473+
if (gate(flags => flags.enableDiscreteEventMicroTasks)) {
474+
// Flush the microtask queue
475+
await null;
476+
477+
// At the end, both counters should equal the total number of clicks
478+
expect(Scheduler).toHaveYielded([
479+
'High-pri count: 8, Low-pri count: 0',
480+
481+
// TODO: with cancellation, this required another flush?
482+
'High-pri count: 8, Low-pri count: 8',
483+
]);
484+
} else {
485+
// At the end, both counters should equal the total number of clicks
486+
expect(Scheduler).toFlushAndYield([
487+
'High-pri count: 8, Low-pri count: 0',
488+
'High-pri count: 8, Low-pri count: 8',
489+
]);
490+
}
478491
expect(button.textContent).toEqual('High-pri count: 8, Low-pri count: 8');
479492
});
480493
});

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import {
9292
warnsIfNotActing,
9393
afterActiveInstanceBlur,
9494
clearContainer,
95+
queueMicrotask,
9596
} from './ReactFiberHostConfig';
9697

9798
import {
@@ -216,6 +217,7 @@ import {
216217
syncNestedUpdateFlag,
217218
} from './ReactProfilerTimer.new';
218219

220+
import {enableDiscreteEventMicroTasks} from 'shared/ReactFeatureFlags';
219221
// DEV stuff
220222
import getComponentName from 'shared/getComponentName';
221223
import ReactStrictModeWarnings from './ReactStrictModeWarnings.new';
@@ -745,6 +747,12 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
745747
ImmediateSchedulerPriority,
746748
performSyncWorkOnRoot.bind(null, root),
747749
);
750+
} else if (
751+
enableDiscreteEventMicroTasks &&
752+
newCallbackPriority === InputDiscreteLanePriority
753+
) {
754+
queueMicrotask(performSyncWorkOnRoot.bind(null, root));
755+
newCallbackNode = null;
748756
} else {
749757
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
750758
newCallbackPriority,

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
disableSchedulerTimeoutInWorkLoop,
3535
enableDoubleInvokingEffects,
3636
skipUnmountedBoundaries,
37+
enableDiscreteEventMicroTasks,
3738
} from 'shared/ReactFeatureFlags';
3839
import ReactSharedInternals from 'shared/ReactSharedInternals';
3940
import invariant from 'shared/invariant';
@@ -92,6 +93,7 @@ import {
9293
warnsIfNotActing,
9394
afterActiveInstanceBlur,
9495
clearContainer,
96+
queueMicrotask,
9597
} from './ReactFiberHostConfig';
9698

9799
import {
@@ -727,6 +729,12 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
727729
ImmediateSchedulerPriority,
728730
performSyncWorkOnRoot.bind(null, root),
729731
);
732+
} else if (
733+
enableDiscreteEventMicroTasks &&
734+
newCallbackPriority === InputDiscreteLanePriority
735+
) {
736+
queueMicrotask(performSyncWorkOnRoot.bind(null, root));
737+
newCallbackNode = null;
730738
} else {
731739
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
732740
newCallbackPriority,

packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3528,6 +3528,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
35283528
});
35293529

35303530
// @gate enableCache
3531+
// @gate !enableDiscreteEventMicroTasks
35313532
it('regression: empty render at high priority causes update to be dropped', async () => {
35323533
// Reproduces a bug where flushDiscreteUpdates starts a new (empty) render
35333534
// pass which cancels a scheduled timeout and causes the fallback never to

packages/react-test-renderer/src/ReactTestHostConfig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export const queueMicrotask =
228228
Promise.resolve(null)
229229
.then(callback)
230230
.catch(handleErrorInNextTick)
231-
: scheduleTimeout;
231+
: scheduleTimeout; // TODO: Determine the best fallback here.
232232

233233
function handleErrorInNextTick(error) {
234234
setTimeout(() => {

packages/shared/ReactFeatureFlags.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,5 @@ export const disableSchedulerTimeoutInWorkLoop = false;
152152

153153
// Experiment to simplify/improve how transitions are scheduled
154154
export const enableTransitionEntanglement = false;
155+
156+
export const enableDiscreteEventMicroTasks = false;

packages/shared/forks/ReactFeatureFlags.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export const enableUseRefAccessWarning = false;
5959
export const enableRecursiveCommitTraversal = false;
6060
export const disableSchedulerTimeoutInWorkLoop = false;
6161
export const enableTransitionEntanglement = false;
62+
export const enableDiscreteEventMicroTasks = false;
6263

6364
// Flow magic to verify the exports of this file match the original version.
6465
// eslint-disable-next-line no-unused-vars

packages/shared/forks/ReactFeatureFlags.native-oss.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
5858
export const enableRecursiveCommitTraversal = false;
5959
export const disableSchedulerTimeoutInWorkLoop = false;
6060
export const enableTransitionEntanglement = false;
61+
export const enableDiscreteEventMicroTasks = false;
6162

6263
// Flow magic to verify the exports of this file match the original version.
6364
// eslint-disable-next-line no-unused-vars

packages/shared/forks/ReactFeatureFlags.test-renderer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
5858
export const enableRecursiveCommitTraversal = false;
5959
export const disableSchedulerTimeoutInWorkLoop = false;
6060
export const enableTransitionEntanglement = false;
61+
export const enableDiscreteEventMicroTasks = false;
6162

6263
// Flow magic to verify the exports of this file match the original version.
6364
// eslint-disable-next-line no-unused-vars

packages/shared/forks/ReactFeatureFlags.test-renderer.native.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
5858
export const enableRecursiveCommitTraversal = false;
5959
export const disableSchedulerTimeoutInWorkLoop = false;
6060
export const enableTransitionEntanglement = false;
61+
export const enableDiscreteEventMicroTasks = false;
6162

6263
// Flow magic to verify the exports of this file match the original version.
6364
// eslint-disable-next-line no-unused-vars

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
5858
export const enableRecursiveCommitTraversal = false;
5959
export const disableSchedulerTimeoutInWorkLoop = false;
6060
export const enableTransitionEntanglement = false;
61+
export const enableDiscreteEventMicroTasks = false;
6162

6263
// Flow magic to verify the exports of this file match the original version.
6364
// eslint-disable-next-line no-unused-vars

packages/shared/forks/ReactFeatureFlags.testing.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
5858
export const enableRecursiveCommitTraversal = false;
5959
export const disableSchedulerTimeoutInWorkLoop = false;
6060
export const enableTransitionEntanglement = false;
61+
export const enableDiscreteEventMicroTasks = false;
6162

6263
// Flow magic to verify the exports of this file match the original version.
6364
// eslint-disable-next-line no-unused-vars

packages/shared/forks/ReactFeatureFlags.testing.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
5858
export const enableRecursiveCommitTraversal = false;
5959
export const disableSchedulerTimeoutInWorkLoop = false;
6060
export const enableTransitionEntanglement = false;
61+
export const enableDiscreteEventMicroTasks = false;
6162

6263
// Flow magic to verify the exports of this file match the original version.
6364
// eslint-disable-next-line no-unused-vars

packages/shared/forks/ReactFeatureFlags.www-dynamic.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,4 @@ export const enableUseRefAccessWarning = __VARIANT__;
5656
export const enableProfilerNestedUpdateScheduledHook = __VARIANT__;
5757
export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
5858
export const enableTransitionEntanglement = __VARIANT__;
59+
export const enableDiscreteEventMicroTasks = __VARIANT__;

packages/shared/forks/ReactFeatureFlags.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const {
3232
disableNativeComponentFrames,
3333
disableSchedulerTimeoutInWorkLoop,
3434
enableTransitionEntanglement,
35+
enableDiscreteEventMicroTasks,
3536
} = dynamicFeatureFlags;
3637

3738
// On WWW, __EXPERIMENTAL__ is used for a new modern build.

0 commit comments

Comments
 (0)