Skip to content

Commit 81880dc

Browse files
rickhanloniikoto
authored andcommitted
Unify InputDiscreteLane with SyncLane (facebook#20968)
* Unify sync priority and input discrete * Fix lint * Use update lane instead * Update sync lane labels
1 parent 82337d5 commit 81880dc

9 files changed

+31
-85
lines changed

packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js

+11-30
Original file line numberDiff line numberDiff line change
@@ -386,63 +386,44 @@ describe('ReactDOMFiberAsync', () => {
386386
});
387387

388388
// @gate experimental
389-
it('ignores discrete events on a pending removed element', () => {
389+
it('ignores discrete events on a pending removed element', async () => {
390390
const disableButtonRef = React.createRef();
391391
const submitButtonRef = React.createRef();
392392

393-
let formSubmitted = false;
394-
395393
function Form() {
396394
const [active, setActive] = React.useState(true);
397395
function disableForm() {
398396
setActive(false);
399397
}
400-
function submitForm() {
401-
formSubmitted = true; // This should not get invoked
402-
}
398+
403399
return (
404400
<div>
405401
<button onClick={disableForm} ref={disableButtonRef}>
406402
Disable
407403
</button>
408-
{active ? (
409-
<button onClick={submitForm} ref={submitButtonRef}>
410-
Submit
411-
</button>
412-
) : null}
404+
{active ? <button ref={submitButtonRef}>Submit</button> : null}
413405
</div>
414406
);
415407
}
416408

417409
const root = ReactDOM.unstable_createRoot(container);
418-
root.render(<Form />);
419-
// Flush
420-
Scheduler.unstable_flushAll();
410+
await act(async () => {
411+
root.render(<Form />);
412+
});
421413

422414
const disableButton = disableButtonRef.current;
423415
expect(disableButton.tagName).toBe('BUTTON');
424416

417+
const submitButton = submitButtonRef.current;
418+
expect(submitButton.tagName).toBe('BUTTON');
419+
425420
// Dispatch a click event on the Disable-button.
426421
const firstEvent = document.createEvent('Event');
427422
firstEvent.initEvent('click', true, true);
428423
disableButton.dispatchEvent(firstEvent);
429424

430-
// There should now be a pending update to disable the form.
431-
432-
// This should not have flushed yet since it's in concurrent mode.
433-
const submitButton = submitButtonRef.current;
434-
expect(submitButton.tagName).toBe('BUTTON');
435-
436-
// In the meantime, we can dispatch a new client event on the submit button.
437-
const secondEvent = document.createEvent('Event');
438-
secondEvent.initEvent('click', true, true);
439-
// This should force the pending update to flush which disables the submit button before the event is invoked.
440-
submitButton.dispatchEvent(secondEvent);
441-
442-
// Therefore the form should never have been submitted.
443-
expect(formSubmitted).toBe(false);
444-
445-
expect(submitButtonRef.current).toBe(null);
425+
// The click event is flushed synchronously, even in concurrent mode.
426+
expect(submitButton.current).toBe(undefined);
446427
});
447428

448429
// @gate experimental

packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js

+3-8
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
6767
}
6868

6969
const root = ReactDOM.unstable_createRoot(container);
70-
root.render(<Form />);
71-
// Flush
72-
Scheduler.unstable_flushAll();
70+
await act(() => {
71+
root.render(<Form />);
72+
});
7373

7474
const disableButton = disableButtonRef.current;
7575
expect(disableButton.tagName).toBe('BUTTON');
@@ -81,11 +81,6 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
8181
dispatchAndSetCurrentEvent(disableButton, firstEvent),
8282
).toErrorDev(['An update to Form inside a test was not wrapped in act']);
8383

84-
// There should now be a pending update to disable the form.
85-
// This should not have flushed yet since it's in concurrent mode.
86-
const submitButton = submitButtonRef.current;
87-
expect(submitButton.tagName).toBe('BUTTON');
88-
8984
// Discrete events should be flushed in a microtask.
9085
// Verify that the second button was removed.
9186
await null;

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ describe('ChangeEventPlugin', () => {
685685
});
686686

687687
// @gate experimental
688-
it('is async for non-input events', async () => {
688+
it('is sync for non-input events', async () => {
689689
const root = ReactDOM.unstable_createRoot(container);
690690
let input;
691691

@@ -724,9 +724,6 @@ describe('ChangeEventPlugin', () => {
724724
input.dispatchEvent(
725725
new Event('click', {bubbles: true, cancelable: true}),
726726
);
727-
// Nothing should have changed
728-
expect(Scheduler).toHaveYielded([]);
729-
expect(input.value).toBe('initial');
730727

731728
// Flush microtask queue.
732729
await null;

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

+13-24
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ describe('SimpleEventPlugin', function() {
240240
});
241241

242242
// @gate experimental
243-
it('flushes pending interactive work before extracting event handler', () => {
243+
it('flushes pending interactive work before exiting event handler', () => {
244244
container = document.createElement('div');
245245
const root = ReactDOM.unstable_createRoot(container);
246246
document.body.appendChild(container);
@@ -292,17 +292,14 @@ describe('SimpleEventPlugin', function() {
292292
expect(Scheduler).toHaveYielded([
293293
// The handler fired
294294
'Side-effect',
295-
// but the component did not re-render yet, because it's async
295+
// The component re-rendered synchronously, even in concurrent mode.
296+
'render button: disabled',
296297
]);
297298

298299
// Click the button again
299300
click();
300301
expect(Scheduler).toHaveYielded([
301-
// Before handling this second click event, the previous interactive
302-
// update is flushed
303-
'render button: disabled',
304-
// The event handler was removed from the button, so there's no second
305-
// side-effect
302+
// The event handler was removed from the button, so there's no effect.
306303
]);
307304

308305
// The handler should not fire again no matter how many times we
@@ -359,8 +356,8 @@ describe('SimpleEventPlugin', function() {
359356

360357
// Click the button a single time
361358
click();
362-
// The counter should not have updated yet because it's async
363-
expect(button.textContent).toEqual('Count: 0');
359+
// The counter should update synchronously, even in concurrent mode.
360+
expect(button.textContent).toEqual('Count: 1');
364361

365362
// Click the button many more times
366363
await TestUtils.act(async () => {
@@ -442,15 +439,10 @@ describe('SimpleEventPlugin', function() {
442439
button.dispatchEvent(event);
443440
}
444441

445-
// Click the button a single time
446-
click();
447-
// Nothing should flush on the first click.
448-
expect(Scheduler).toHaveYielded([]);
449-
// Click again. This will force the previous discrete update to flush. But
450-
// only the high-pri count will increase.
442+
// Click the button a single time.
443+
// This will flush at the end of the event, even in concurrent mode.
451444
click();
452445
expect(Scheduler).toHaveYielded(['High-pri count: 1, Low-pri count: 0']);
453-
expect(button.textContent).toEqual('High-pri count: 1, Low-pri count: 0');
454446

455447
// Click the button many more times
456448
click();
@@ -460,7 +452,7 @@ describe('SimpleEventPlugin', function() {
460452
click();
461453
click();
462454

463-
// Flush the remaining work.
455+
// Each update should synchronously flush, even in concurrent mode.
464456
expect(Scheduler).toHaveYielded([
465457
'High-pri count: 2, Low-pri count: 0',
466458
'High-pri count: 3, Low-pri count: 0',
@@ -470,16 +462,13 @@ describe('SimpleEventPlugin', function() {
470462
'High-pri count: 7, Low-pri count: 0',
471463
]);
472464

473-
// Flush the microtask queue
474-
await null;
475-
476-
// At the end, both counters should equal the total number of clicks
477-
expect(Scheduler).toHaveYielded(['High-pri count: 8, Low-pri count: 0']);
465+
// Now flush the scheduler to apply the transition updates.
466+
// At the end, both counters should equal the total number of clicks.
478467
expect(Scheduler).toFlushAndYield([
479-
'High-pri count: 8, Low-pri count: 8',
468+
'High-pri count: 7, Low-pri count: 7',
480469
]);
481470

482-
expect(button.textContent).toEqual('High-pri count: 8, Low-pri count: 8');
471+
expect(button.textContent).toEqual('High-pri count: 7, Low-pri count: 7');
483472
});
484473
});
485474

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ export function findUpdateLane(lanePriority: LanePriority): Lane {
566566
case SyncBatchedLanePriority:
567567
return SyncBatchedLane;
568568
case InputDiscreteLanePriority:
569-
return InputDiscreteLane;
569+
return SyncLane;
570570
case InputContinuousLanePriority:
571571
return InputContinuousLane;
572572
case DefaultLanePriority:

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ export function findUpdateLane(lanePriority: LanePriority): Lane {
566566
case SyncBatchedLanePriority:
567567
return SyncBatchedLane;
568568
case InputDiscreteLanePriority:
569-
return InputDiscreteLane;
569+
return SyncLane;
570570
case InputContinuousLanePriority:
571571
return InputContinuousLane;
572572
case DefaultLanePriority:

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

-7
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ import {
9090
clearContainer,
9191
getCurrentEventPriority,
9292
supportsMicrotasks,
93-
scheduleMicrotask,
9493
} from './ReactFiberHostConfig';
9594

9695
import {
@@ -737,12 +736,6 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
737736
ImmediateSchedulerPriority,
738737
performSyncWorkOnRoot.bind(null, root),
739738
);
740-
} else if (
741-
supportsMicrotasks &&
742-
newCallbackPriority === InputDiscreteLanePriority
743-
) {
744-
scheduleMicrotask(performSyncWorkOnRoot.bind(null, root));
745-
newCallbackNode = null;
746739
} else {
747740
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
748741
newCallbackPriority,

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

-7
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ import {
9090
clearContainer,
9191
getCurrentEventPriority,
9292
supportsMicrotasks,
93-
scheduleMicrotask,
9493
} from './ReactFiberHostConfig';
9594

9695
import {
@@ -737,12 +736,6 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
737736
ImmediateSchedulerPriority,
738737
performSyncWorkOnRoot.bind(null, root),
739738
);
740-
} else if (
741-
supportsMicrotasks &&
742-
newCallbackPriority === InputDiscreteLanePriority
743-
) {
744-
scheduleMicrotask(performSyncWorkOnRoot.bind(null, root));
745-
newCallbackNode = null;
746739
} else {
747740
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
748741
newCallbackPriority,

packages/react-reconciler/src/__tests__/SchedulingProfilerLabels-test.internal.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,7 @@ describe('SchedulingProfiler labels', () => {
140140
targetRef.current.click();
141141
});
142142
expect(clearedMarks).toContain(
143-
`--schedule-state-update-${formatLanes(
144-
ReactFiberLane.InputDiscreteLane,
145-
)}-App`,
143+
`--schedule-state-update-${formatLanes(ReactFiberLane.SyncLane)}-App`,
146144
);
147145
});
148146

0 commit comments

Comments
 (0)