Skip to content

Commit 4ddabc5

Browse files
committed
Use SyncLane for discrete event hydration
Discrete event hydration doesn't need to be interruptible, since there's nothing higher priority than discrete events. So we can use SyncLane instead of a special hydration lane.
1 parent 6d3ecb7 commit 4ddabc5

File tree

5 files changed

+121
-105
lines changed

5 files changed

+121
-105
lines changed

packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js

Lines changed: 63 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,17 +2187,17 @@ describe('ReactDOMServerPartialHydration', () => {
21872187
expect(container.textContent).toBe('Click meHello');
21882188

21892189
// We're now partially hydrated.
2190-
a.click();
2190+
await act(async () => {
2191+
a.click();
2192+
});
21912193
expect(clicks).toBe(0);
21922194

21932195
// Resolving the promise so that rendering can complete.
2194-
suspend = false;
2195-
resolve();
2196-
await promise;
2197-
2198-
Scheduler.unstable_flushAll();
2199-
jest.runAllTimers();
2200-
2196+
await act(async () => {
2197+
suspend = false;
2198+
resolve();
2199+
await promise;
2200+
});
22012201
expect(clicks).toBe(1);
22022202

22032203
expect(container.textContent).toBe('Hello');
@@ -2270,18 +2270,19 @@ describe('ReactDOMServerPartialHydration', () => {
22702270
jest.runAllTimers();
22712271

22722272
// We're now partially hydrated.
2273-
a.click();
2273+
await act(async () => {
2274+
a.click();
2275+
});
22742276
// We should not have invoked the event yet because we're not
22752277
// yet hydrated.
22762278
expect(onEvent).toHaveBeenCalledTimes(0);
22772279

22782280
// Resolving the promise so that rendering can complete.
2279-
suspend = false;
2280-
resolve();
2281-
await promise;
2282-
2283-
Scheduler.unstable_flushAll();
2284-
jest.runAllTimers();
2281+
await act(async () => {
2282+
suspend = false;
2283+
resolve();
2284+
await promise;
2285+
});
22852286

22862287
expect(onEvent).toHaveBeenCalledTimes(2);
22872288

@@ -2344,25 +2345,27 @@ describe('ReactDOMServerPartialHydration', () => {
23442345
root.render(<App />);
23452346

23462347
// We'll do one click before hydrating.
2347-
a.click();
2348+
await act(async () => {
2349+
a.click();
2350+
});
23482351
// This should be delayed.
23492352
expect(clicks).toBe(0);
23502353

23512354
Scheduler.unstable_flushAll();
23522355
jest.runAllTimers();
23532356

23542357
// We're now partially hydrated.
2355-
a.click();
2358+
await act(async () => {
2359+
a.click();
2360+
});
23562361
expect(clicks).toBe(0);
23572362

23582363
// Resolving the promise so that rendering can complete.
2359-
suspend = false;
2360-
resolve();
2361-
await promise;
2362-
2363-
Scheduler.unstable_flushAll();
2364-
jest.runAllTimers();
2365-
2364+
await act(async () => {
2365+
suspend = false;
2366+
resolve();
2367+
await promise;
2368+
});
23662369
expect(clicks).toBe(2);
23672370

23682371
document.body.removeChild(container);
@@ -2436,19 +2439,19 @@ describe('ReactDOMServerPartialHydration', () => {
24362439
jest.runAllTimers();
24372440

24382441
// We're now partially hydrated.
2439-
a.click();
2442+
await act(async () => {
2443+
a.click();
2444+
});
24402445
// We should not have invoked the event yet because we're not
24412446
// yet hydrated.
24422447
expect(onEvent).toHaveBeenCalledTimes(0);
24432448

24442449
// Resolving the promise so that rendering can complete.
2445-
suspend = false;
2446-
resolve();
2447-
await promise;
2448-
2449-
Scheduler.unstable_flushAll();
2450-
jest.runAllTimers();
2451-
2450+
await act(async () => {
2451+
suspend = false;
2452+
resolve();
2453+
await promise;
2454+
});
24522455
expect(onEvent).toHaveBeenCalledTimes(2);
24532456

24542457
document.body.removeChild(container);
@@ -2510,17 +2513,18 @@ describe('ReactDOMServerPartialHydration', () => {
25102513
jest.runAllTimers();
25112514

25122515
// We're now partially hydrated.
2513-
span.click();
2516+
await act(async () => {
2517+
span.click();
2518+
});
25142519
expect(clicksOnChild).toBe(0);
25152520
expect(clicksOnParent).toBe(0);
25162521

25172522
// Resolving the promise so that rendering can complete.
2518-
suspend = false;
2519-
resolve();
2520-
await promise;
2521-
2522-
Scheduler.unstable_flushAll();
2523-
jest.runAllTimers();
2523+
await act(async () => {
2524+
suspend = false;
2525+
resolve();
2526+
await promise;
2527+
});
25242528

25252529
expect(clicksOnChild).toBe(1);
25262530
// This will be zero due to the stopPropagation.
@@ -2589,16 +2593,17 @@ describe('ReactDOMServerPartialHydration', () => {
25892593
Scheduler.unstable_flushAll();
25902594

25912595
// The Suspense boundary is not yet hydrated.
2592-
a.click();
2596+
await act(async () => {
2597+
a.click();
2598+
});
25932599
expect(clicks).toBe(0);
25942600

25952601
// Resolving the promise so that rendering can complete.
2596-
suspend = false;
2597-
resolve();
2598-
await promise;
2599-
2600-
Scheduler.unstable_flushAll();
2601-
jest.runAllTimers();
2602+
await act(async () => {
2603+
suspend = false;
2604+
resolve();
2605+
await promise;
2606+
});
26022607

26032608
// We're now full hydrated.
26042609

@@ -2858,20 +2863,22 @@ describe('ReactDOMServerPartialHydration', () => {
28582863
expect(container.textContent).toBe('Click meHello');
28592864

28602865
// We're now partially hydrated.
2861-
form.dispatchEvent(
2862-
new Event('submit', {
2863-
bubbles: true,
2864-
}),
2865-
);
2866+
await act(async () => {
2867+
form.dispatchEvent(
2868+
new Event('submit', {
2869+
bubbles: true,
2870+
}),
2871+
);
2872+
});
28662873
expect(submits).toBe(0);
28672874

28682875
// Resolving the promise so that rendering can complete.
2869-
suspend = false;
2870-
resolve();
2871-
await promise;
2876+
await act(async () => {
2877+
suspend = false;
2878+
resolve();
2879+
await promise;
2880+
});
28722881

2873-
Scheduler.unstable_flushAll();
2874-
jest.runAllTimers();
28752882
expect(submits).toBe(1);
28762883
expect(container.textContent).toBe('Hello');
28772884
document.body.removeChild(container);

packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -255,22 +255,25 @@ describe('ReactDOMServerSelectiveHydration', () => {
255255
expect(Scheduler).toHaveYielded([]);
256256

257257
// This click target cannot be hydrated yet because it's suspended.
258-
const result = dispatchClickEvent(spanD);
259-
260-
expect(Scheduler).toHaveYielded(['App']);
261-
262-
expect(result).toBe(true);
263-
264-
// Continuing rendering will render B next.
265-
expect(Scheduler).toFlushAndYield(['B', 'C']);
266-
267-
suspend = false;
268-
resolve();
269-
await promise;
258+
await act(async () => {
259+
const result = dispatchClickEvent(spanD);
260+
expect(result).toBe(true);
261+
});
262+
expect(Scheduler).toHaveYielded([
263+
'App',
264+
// Continuing rendering will render B next.
265+
'B',
266+
'C',
267+
]);
270268

269+
await act(async () => {
270+
suspend = false;
271+
resolve();
272+
await promise;
273+
});
271274
// After the click, we should prioritize D and the Click first,
272275
// and only after that render A and C.
273-
expect(Scheduler).toFlushAndYield(['D', 'Clicked D', 'A']);
276+
expect(Scheduler).toHaveYielded(['D', 'Clicked D', 'A']);
274277

275278
document.body.removeChild(container);
276279
});
@@ -348,13 +351,15 @@ describe('ReactDOMServerSelectiveHydration', () => {
348351

349352
expect(Scheduler).toHaveYielded(['App']);
350353

351-
suspend = false;
352-
resolve();
353-
await promise;
354+
await act(async () => {
355+
suspend = false;
356+
resolve();
357+
await promise;
358+
});
354359

355360
// We should prioritize hydrating A, C and D first since we clicked in
356361
// them. Only after they're done will we hydrate B.
357-
expect(Scheduler).toFlushAndYield([
362+
expect(Scheduler).toHaveYielded([
358363
'A',
359364
'Clicked A',
360365
'C',
@@ -506,21 +511,21 @@ describe('ReactDOMServerSelectiveHydration', () => {
506511
// Nothing has been hydrated so far.
507512
expect(Scheduler).toHaveYielded([]);
508513

509-
const target = createEventTarget(spanD);
510-
target.virtualclick();
511-
512-
expect(Scheduler).toHaveYielded(['App']);
513-
514514
// Continuing rendering will render B next.
515-
expect(Scheduler).toFlushAndYield(['B', 'C']);
516-
517-
suspend = false;
518-
resolve();
519-
await promise;
515+
await act(async () => {
516+
const target = createEventTarget(spanD);
517+
target.virtualclick();
518+
});
519+
expect(Scheduler).toHaveYielded(['App', 'B', 'C']);
520520

521521
// After the click, we should prioritize D and the Click first,
522522
// and only after that render A and C.
523-
expect(Scheduler).toFlushAndYield(['D', 'Clicked D', 'A']);
523+
await act(async () => {
524+
suspend = false;
525+
resolve();
526+
await promise;
527+
});
528+
expect(Scheduler).toHaveYielded(['D', 'Clicked D', 'A']);
524529

525530
document.body.removeChild(container);
526531
});
@@ -602,13 +607,15 @@ describe('ReactDOMServerSelectiveHydration', () => {
602607

603608
expect(Scheduler).toHaveYielded(['App']);
604609

605-
suspend = false;
606-
resolve();
607-
await promise;
610+
await act(async () => {
611+
suspend = false;
612+
resolve();
613+
await promise;
614+
});
608615

609616
// We should prioritize hydrating A, C and D first since we clicked in
610617
// them. Only after they're done will we hydrate B.
611-
expect(Scheduler).toFlushAndYield([
618+
expect(Scheduler).toHaveYielded([
612619
'A',
613620
'Clicked A',
614621
'C',
@@ -701,17 +708,19 @@ describe('ReactDOMServerSelectiveHydration', () => {
701708

702709
expect(Scheduler).toHaveYielded(['App']);
703710

704-
suspend = false;
705-
resolve();
706-
await promise;
711+
await act(async () => {
712+
suspend = false;
713+
resolve();
714+
await promise;
715+
});
707716

708717
// We should prioritize hydrating D first because we clicked it.
709718
// Next we should hydrate C since that's the current hover target.
710719
// To simplify implementation details we hydrate both B and C at
711720
// the same time since B was already scheduled.
712721
// This is ok because it will at least not continue for nested
713722
// boundary. See the next test below.
714-
expect(Scheduler).toFlushAndYield([
723+
expect(Scheduler).toHaveYielded([
715724
'D',
716725
'Clicked D',
717726
'B', // Ideally this should be later.

packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ describe('DOMPluginEventSystem', () => {
6767
ReactDOM = require('react-dom');
6868
Scheduler = require('scheduler');
6969
ReactDOMServer = require('react-dom/server');
70+
act = require('react-dom/test-utils').unstable_concurrentAct;
7071
container = document.createElement('div');
7172
document.body.appendChild(container);
7273
startNativeEventListenerClearDown();
@@ -636,16 +637,17 @@ describe('DOMPluginEventSystem', () => {
636637
Scheduler.unstable_flushAll();
637638

638639
// The Suspense boundary is not yet hydrated.
639-
a.click();
640+
await act(async () => {
641+
a.click();
642+
});
640643
expect(clicks).toBe(0);
641644

642645
// Resolving the promise so that rendering can complete.
643-
suspend = false;
644-
resolve();
645-
await promise;
646-
647-
Scheduler.unstable_flushAll();
648-
jest.runAllTimers();
646+
await act(async () => {
647+
suspend = false;
648+
resolve();
649+
await promise;
650+
});
649651

650652
// We're now full hydrated.
651653

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ import {
7878
import {StrictLegacyMode} from './ReactTypeOfMode';
7979
import {
8080
SyncLane,
81-
InputDiscreteHydrationLane,
8281
SelectiveHydrationLane,
8382
NoTimestamp,
8483
getHighestPriorityPendingLanes,
@@ -388,7 +387,7 @@ export function attemptSynchronousHydration(fiber: Fiber): void {
388387
// If we're still blocked after this, we need to increase
389388
// the priority of any promises resolving within this
390389
// boundary so that they next attempt also has higher pri.
391-
const retryLane = InputDiscreteHydrationLane;
390+
const retryLane = SyncLane;
392391
markRetryLaneIfNotHydrated(fiber, retryLane);
393392
break;
394393
}
@@ -422,7 +421,7 @@ export function attemptDiscreteHydration(fiber: Fiber): void {
422421
return;
423422
}
424423
const eventTime = requestEventTime();
425-
const lane = InputDiscreteHydrationLane;
424+
const lane = SyncLane;
426425
scheduleUpdateOnFiber(fiber, lane, eventTime);
427426
markRetryLaneIfNotHydrated(fiber, lane);
428427
}

0 commit comments

Comments
 (0)