Clean up enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay (#26521)
This flag is already enabled everywhere except for www, which is blocked by a few tests that assert on the old behavior. Once www is ready, I'll land this.
Andrew Clark committed
Mar 31, 2023 at 10:25 UTC
8310854cebba4d1f404e65ff2064825ee76d78e2
14 files changed
+74
-546
packages/react-dom-bindings/src/events/ReactDOMEventListener.js
+1
-115
@@ -12,11 +12,9 @@ import type {AnyNativeEvent} from '../events/PluginModuleType';
12
import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
13
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
14
import type {DOMEventName} from '../events/DOMEventNames';
15
-import {enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay} from 'shared/ReactFeatureFlags';
15
+
16
import {
17
isDiscreteEventThatRequiresHydration,
18
- queueDiscreteEvent,
19
- hasQueuedDiscreteEvents,
18
clearIfContinuousEvent,
19
queueIfContinuousEvent,
20
} from './ReactDOMEventReplaying';
@@ -156,119 +154,7 @@ export function dispatchEvent(
154
if (!_enabled) {
155
return;
156
}
159
- if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
160
- dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay(
161
- domEventName,
162
- eventSystemFlags,
163
- targetContainer,
164
- nativeEvent,
165
- );
166
- } else {
167
- dispatchEventOriginal(
168
- domEventName,
169
- eventSystemFlags,
170
- targetContainer,
171
- nativeEvent,
172
- );
173
- }
174
-}
175
-
176
-function dispatchEventOriginal(
177
- domEventName: DOMEventName,
178
- eventSystemFlags: EventSystemFlags,
179
- targetContainer: EventTarget,
180
- nativeEvent: AnyNativeEvent,
181
-) {
182
- // TODO: replaying capture phase events is currently broken
183
- // because we used to do it during top-level native bubble handlers
184
- // but now we use different bubble and capture handlers.
185
- // In eager mode, we attach capture listeners early, so we need
186
- // to filter them out until we fix the logic to handle them correctly.
187
- const allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0;
157
189
- if (
190
- allowReplay &&
191
- hasQueuedDiscreteEvents() &&
192
- isDiscreteEventThatRequiresHydration(domEventName)
193
- ) {
194
- // If we already have a queue of discrete events, and this is another discrete
195
- // event, then we can't dispatch it regardless of its target, since they
196
- // need to dispatch in order.
197
- queueDiscreteEvent(
198
- null, // Flags that we're not actually blocked on anything as far as we know.
199
- domEventName,
200
- eventSystemFlags,
201
- targetContainer,
202
- nativeEvent,
203
- );
204
- return;
205
- }
206
-
207
- const blockedOn = findInstanceBlockingEvent(
208
- domEventName,
209
- eventSystemFlags,
210
- targetContainer,
211
- nativeEvent,
212
- );
213
- if (blockedOn === null) {
214
- dispatchEventForPluginEventSystem(
215
- domEventName,
216
- eventSystemFlags,
217
- nativeEvent,
218
- return_targetInst,
219
- targetContainer,
220
- );
221
- if (allowReplay) {
222
- clearIfContinuousEvent(domEventName, nativeEvent);
223
- }
224
- return;
225
- }
226
-
227
- if (allowReplay) {
228
- if (isDiscreteEventThatRequiresHydration(domEventName)) {
229
- // This to be replayed later once the target is available.
230
- queueDiscreteEvent(
231
- blockedOn,
232
- domEventName,
233
- eventSystemFlags,
234
- targetContainer,
235
- nativeEvent,
236
- );
237
- return;
238
- }
239
- if (
240
- queueIfContinuousEvent(
241
- blockedOn,
242
- domEventName,
243
- eventSystemFlags,
244
- targetContainer,
245
- nativeEvent,
246
- )
247
- ) {
248
- return;
249
- }
250
- // We need to clear only if we didn't queue because
251
- // queueing is accumulative.
252
- clearIfContinuousEvent(domEventName, nativeEvent);
253
- }
254
-
255
- // This is not replayable so we'll invoke it but without a target,
256
- // in case the event system needs to trace it.
257
- dispatchEventForPluginEventSystem(
258
- domEventName,
259
- eventSystemFlags,
260
- nativeEvent,
261
- null,
262
- targetContainer,
263
- );
264
-}
265
-
266
-function dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay(
267
- domEventName: DOMEventName,
268
- eventSystemFlags: EventSystemFlags,
269
- targetContainer: EventTarget,
270
- nativeEvent: AnyNativeEvent,
271
-) {
158
let blockedOn = findInstanceBlockingEvent(
159
domEventName,
160
eventSystemFlags,
packages/react-dom-bindings/src/events/ReactDOMEventReplaying.js
+10
-120
@@ -14,7 +14,6 @@ import type {EventSystemFlags} from './EventSystemFlags';
14
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
15
import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities';
16
17
-import {enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay} from 'shared/ReactFeatureFlags';
17
import {
18
unstable_scheduleCallback as scheduleCallback,
19
unstable_NormalPriority as NormalPriority,
@@ -24,12 +23,8 @@ import {
23
getContainerFromFiber,
24
getSuspenseInstanceFromFiber,
25
} from 'react-reconciler/src/ReactFiberTreeReflection';
27
-import {
28
- findInstanceBlockingEvent,
29
- return_targetInst,
30
-} from './ReactDOMEventListener';
26
+import {findInstanceBlockingEvent} from './ReactDOMEventListener';
27
import {setReplayingEvent, resetReplayingEvent} from './CurrentReplayingEvent';
32
-import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
28
import {
29
getInstanceFromNode,
30
getClosestInstanceFromNode,
@@ -39,8 +34,6 @@ import {isHigherEventPriority} from 'react-reconciler/src/ReactEventPriorities';
34
import {isRootDehydrated} from 'react-reconciler/src/ReactFiberShellHydration';
35
36
import {
42
- attemptSynchronousHydration,
43
- attemptDiscreteHydration,
37
attemptContinuousHydration,
38
attemptHydrationAtCurrentPriority,
39
} from 'react-reconciler/src/ReactFiberReconciler';
@@ -150,48 +143,6 @@ function createQueuedReplayableEvent(
143
};
144
}
145
153
-export function queueDiscreteEvent(
154
- blockedOn: null | Container | SuspenseInstance,
155
- domEventName: DOMEventName,
156
- eventSystemFlags: EventSystemFlags,
157
- targetContainer: EventTarget,
158
- nativeEvent: AnyNativeEvent,
159
-): void {
160
- if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
161
- return;
162
- }
163
- const queuedEvent = createQueuedReplayableEvent(
164
- blockedOn,
165
- domEventName,
166
- eventSystemFlags,
167
- targetContainer,
168
- nativeEvent,
169
- );
170
- queuedDiscreteEvents.push(queuedEvent);
171
- if (queuedDiscreteEvents.length === 1) {
172
- // If this was the first discrete event, we might be able to
173
- // synchronously unblock it so that preventDefault still works.
174
- while (queuedEvent.blockedOn !== null) {
175
- const fiber = getInstanceFromNode(queuedEvent.blockedOn);
176
- if (fiber === null) {
177
- break;
178
- }
179
- attemptSynchronousHydration(fiber);
180
- if (queuedEvent.blockedOn === null) {
181
- // We got unblocked by hydration. Let's try again.
182
- replayUnblockedEvents();
183
- // If we're reblocked, on an inner boundary, we might need
184
- // to attempt hydrating that one.
185
- continue;
186
- } else {
187
- // We're still blocked from hydration, we have to give up
188
- // and replay later.
189
- break;
190
- }
191
- }
192
- }
193
-}
194
-
146
// Resets the replaying for this type of continuous event to no event.
147
export function clearIfContinuousEvent(
148
domEventName: DOMEventName,
@@ -433,26 +384,14 @@ function attemptReplayContinuousQueuedEvent(
384
queuedEvent.nativeEvent,
385
);
386
if (nextBlockedOn === null) {
436
- if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
437
- const nativeEvent = queuedEvent.nativeEvent;
438
- const nativeEventClone = new nativeEvent.constructor(
439
- nativeEvent.type,
440
- (nativeEvent: any),
441
- );
442
- setReplayingEvent(nativeEventClone);
443
- nativeEvent.target.dispatchEvent(nativeEventClone);
444
- resetReplayingEvent();
445
- } else {
446
- setReplayingEvent(queuedEvent.nativeEvent);
447
- dispatchEventForPluginEventSystem(
448
- queuedEvent.domEventName,
449
- queuedEvent.eventSystemFlags,
450
- queuedEvent.nativeEvent,
451
- return_targetInst,
452
- targetContainer,
453
- );
454
- resetReplayingEvent();
455
- }
387
+ const nativeEvent = queuedEvent.nativeEvent;
388
+ const nativeEventClone = new nativeEvent.constructor(
389
+ nativeEvent.type,
390
+ (nativeEvent: any),
391
+ );
392
+ setReplayingEvent(nativeEventClone);
393
+ nativeEvent.target.dispatchEvent(nativeEventClone);
394
+ resetReplayingEvent();
395
} else {
396
// We're still blocked. Try again later.
397
const fiber = getInstanceFromNode(nextBlockedOn);
@@ -480,56 +419,7 @@ function attemptReplayContinuousQueuedEventInMap(
419
420
function replayUnblockedEvents() {
421
hasScheduledReplayAttempt = false;
483
- if (!enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
484
- // First replay discrete events.
485
- while (queuedDiscreteEvents.length > 0) {
486
- const nextDiscreteEvent = queuedDiscreteEvents[0];
487
- if (nextDiscreteEvent.blockedOn !== null) {
488
- // We're still blocked.
489
- // Increase the priority of this boundary to unblock
490
- // the next discrete event.
491
- const fiber = getInstanceFromNode(nextDiscreteEvent.blockedOn);
492
- if (fiber !== null) {
493
- attemptDiscreteHydration(fiber);
494
- }
495
- break;
496
- }
497
- const targetContainers = nextDiscreteEvent.targetContainers;
498
- while (targetContainers.length > 0) {
499
- const targetContainer = targetContainers[0];
500
- const nextBlockedOn = findInstanceBlockingEvent(
501
- nextDiscreteEvent.domEventName,
502
- nextDiscreteEvent.eventSystemFlags,
503
- targetContainer,
504
- nextDiscreteEvent.nativeEvent,
505
- );
506
- if (nextBlockedOn === null) {
507
- // This whole function is in !enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
508
- // so we don't need the new replay behavior code branch.
509
- setReplayingEvent(nextDiscreteEvent.nativeEvent);
510
- dispatchEventForPluginEventSystem(
511
- nextDiscreteEvent.domEventName,
512
- nextDiscreteEvent.eventSystemFlags,
513
- nextDiscreteEvent.nativeEvent,
514
- return_targetInst,
515
- targetContainer,
516
- );
517
- resetReplayingEvent();
518
- } else {
519
- // We're still blocked. Try again later.
520
- nextDiscreteEvent.blockedOn = nextBlockedOn;
521
- break;
522
- }
523
- // This target container was successfully dispatched. Try the next.
524
- targetContainers.shift();
525
- }
526
- if (nextDiscreteEvent.blockedOn === null) {
527
- // We've successfully replayed the first event. Let's try the next one.
528
- queuedDiscreteEvents.shift();
529
- }
530
- }
531
- }
532
- // Next replay any continuous events.
422
+ // Replay any continuous events.
423
if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) {
424
queuedFocus = null;
425
}
packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js
+13
-79
@@ -2392,18 +2392,9 @@ describe('ReactDOMServerPartialHydration', () => {
2392
await promise;
2393
});
2394
2395
- if (
2396
- gate(
2397
- flags =>
2398
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
2399
- )
2400
- ) {
2401
- expect(clicks).toBe(0);
2402
- expect(container.textContent).toBe('Click meHello');
2403
- } else {
2404
- expect(clicks).toBe(1);
2405
- expect(container.textContent).toBe('Hello');
2406
- }
2395
+ expect(clicks).toBe(0);
2396
+ expect(container.textContent).toBe('Click meHello');
2397
+
2398
document.body.removeChild(container);
2399
});
2400
@@ -2484,16 +2475,7 @@ describe('ReactDOMServerPartialHydration', () => {
2475
await promise;
2476
});
2477
2487
- if (
2488
- gate(
2489
- flags =>
2490
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
2491
- )
2492
- ) {
2493
- expect(onEvent).toHaveBeenCalledTimes(0);
2494
- } else {
2495
- expect(onEvent).toHaveBeenCalledTimes(2);
2496
- }
2478
+ expect(onEvent).toHaveBeenCalledTimes(0);
2479
2480
document.body.removeChild(container);
2481
});
@@ -2573,16 +2555,7 @@ describe('ReactDOMServerPartialHydration', () => {
2555
await promise;
2556
});
2557
2576
- if (
2577
- gate(
2578
- flags =>
2579
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
2580
- )
2581
- ) {
2582
- expect(clicks).toBe(0);
2583
- } else {
2584
- expect(clicks).toBe(2);
2585
- }
2558
+ expect(clicks).toBe(0);
2559
2560
document.body.removeChild(container);
2561
});
@@ -2666,16 +2639,8 @@ describe('ReactDOMServerPartialHydration', () => {
2639
resolve();
2640
await promise;
2641
});
2669
- if (
2670
- gate(
2671
- flags =>
2672
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
2673
- )
2674
- ) {
2675
- expect(onEvent).toHaveBeenCalledTimes(0);
2676
- } else {
2677
- expect(onEvent).toHaveBeenCalledTimes(2);
2678
- }
2642
+
2643
+ expect(onEvent).toHaveBeenCalledTimes(0);
2644
2645
document.body.removeChild(container);
2646
});
@@ -2746,19 +2711,8 @@ describe('ReactDOMServerPartialHydration', () => {
2711
await promise;
2712
});
2713
2749
- if (
2750
- gate(
2751
- flags =>
2752
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
2753
- )
2754
- ) {
2755
- expect(clicksOnChild).toBe(0);
2756
- expect(clicksOnParent).toBe(0);
2757
- } else {
2758
- expect(clicksOnChild).toBe(1);
2759
- // This will be zero due to the stopPropagation.
2760
- expect(clicksOnParent).toBe(0);
2761
- }
2714
+ expect(clicksOnChild).toBe(0);
2715
+ expect(clicksOnParent).toBe(0);
2716
2717
document.body.removeChild(container);
2718
});
@@ -2830,17 +2784,7 @@ describe('ReactDOMServerPartialHydration', () => {
2784
await promise;
2785
});
2786
2833
- // We're now full hydrated.
2834
- if (
2835
- gate(
2836
- flags =>
2837
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
2838
- )
2839
- ) {
2840
- expect(clicks).toBe(0);
2841
- } else {
2842
- expect(clicks).toBe(1);
2843
- }
2787
+ expect(clicks).toBe(0);
2788
2789
document.body.removeChild(parentContainer);
2790
});
@@ -3105,19 +3049,9 @@ describe('ReactDOMServerPartialHydration', () => {
3049
await promise;
3050
});
3051
3108
- if (
3109
- gate(
3110
- flags =>
3111
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
3112
- )
3113
- ) {
3114
- // discrete event not replayed
3115
- expect(submits).toBe(0);
3116
- expect(container.textContent).toBe('Click meHello');
3117
- } else {
3118
- expect(submits).toBe(1);
3119
- expect(container.textContent).toBe('Hello');
3120
- }
3052
+ // discrete event not replayed
3053
+ expect(submits).toBe(0);
3054
+ expect(container.textContent).toBe('Click meHello');
3055
3056
document.body.removeChild(container);
3057
});
packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js
+49
-186
@@ -293,18 +293,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
293
await promise;
294
});
295
296
- if (
297
- gate(
298
- flags =>
299
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
300
- )
301
- ) {
302
- assertLog(['D', 'A']);
303
- } else {
304
- // After the click, we should prioritize D and the Click first,
305
- // and only after that render A and C.
306
- assertLog(['D', 'Clicked D', 'A']);
307
- }
296
+ assertLog(['D', 'A']);
297
298
document.body.removeChild(container);
299
});
@@ -378,16 +367,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
367
dispatchClickEvent(spanC);
368
dispatchClickEvent(spanD);
369
381
- if (
382
- gate(
383
- flags =>
384
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
385
- )
386
- ) {
387
- assertLog(['App', 'C', 'Clicked C']);
388
- } else {
389
- assertLog(['App']);
390
- }
370
+ assertLog(['App', 'C', 'Clicked C']);
371
372
await act(async () => {
373
suspend = false;
@@ -395,29 +375,12 @@ describe('ReactDOMServerSelectiveHydration', () => {
375
await promise;
376
});
377
398
- if (
399
- ReactFeatureFlags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
400
- ) {
401
- assertLog([
402
- 'A',
403
- 'D',
404
- // B should render last since it wasn't clicked.
405
- 'B',
406
- ]);
407
- } else {
408
- // We should prioritize hydrating A, C and D first since we clicked in
409
- // them. Only after they're done will we hydrate B.
410
- assertLog([
411
- 'A',
412
- 'Clicked A',
413
- 'C',
414
- 'Clicked C',
415
- 'D',
416
- 'Clicked D',
417
- // B should render last since it wasn't clicked.
418
- 'B',
419
- ]);
420
- }
378
+ assertLog([
379
+ 'A',
380
+ 'D',
381
+ // B should render last since it wasn't clicked.
382
+ 'B',
383
+ ]);
384
385
document.body.removeChild(container);
386
});
@@ -571,17 +534,9 @@ describe('ReactDOMServerSelectiveHydration', () => {
534
resolve();
535
await promise;
536
});
574
- if (
575
- gate(
576
- flags =>
577
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
578
- )
579
- ) {
580
- // no replay
581
- assertLog(['D', 'A']);
582
- } else {
583
- assertLog(['D', 'Clicked D', 'A']);
584
- }
537
+
538
+ // no replay
539
+ assertLog(['D', 'A']);
540
541
document.body.removeChild(container);
542
});
@@ -660,42 +615,20 @@ describe('ReactDOMServerSelectiveHydration', () => {
615
createEventTarget(spanC).virtualclick();
616
createEventTarget(spanD).virtualclick();
617
663
- if (
664
- ReactFeatureFlags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
665
- ) {
666
- assertLog(['App', 'C', 'Clicked C']);
667
- } else {
668
- assertLog(['App']);
669
- }
618
+ assertLog(['App', 'C', 'Clicked C']);
619
+
620
await act(async () => {
621
suspend = false;
622
resolve();
623
await promise;
624
});
625
676
- if (
677
- ReactFeatureFlags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
678
- ) {
679
- assertLog([
680
- 'A',
681
- 'D',
682
- // B should render last since it wasn't clicked.
683
- 'B',
684
- ]);
685
- } else {
686
- // We should prioritize hydrating A, C and D first since we clicked in
687
- // them. Only after they're done will we hydrate B.
688
- assertLog([
689
- 'A',
690
- 'Clicked A',
691
- 'C',
692
- 'Clicked C',
693
- 'D',
694
- 'Clicked D',
695
- // B should render last since it wasn't clicked.
696
- 'B',
697
- ]);
698
- }
626
+ assertLog([
627
+ 'A',
628
+ 'D',
629
+ // B should render last since it wasn't clicked.
630
+ 'B',
631
+ ]);
632
633
document.body.removeChild(container);
634
});
@@ -779,37 +712,15 @@ describe('ReactDOMServerSelectiveHydration', () => {
712
resolve();
713
});
714
782
- if (
783
- gate(
784
- flags =>
785
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
786
- )
787
- ) {
788
- // We should prioritize hydrating D first because we clicked it.
789
- // but event isnt replayed
790
- assertLog([
791
- 'D',
792
- 'B', // Ideally this should be later.
793
- 'C',
794
- 'Hover C',
795
- 'A',
796
- ]);
797
- } else {
798
- // We should prioritize hydrating D first because we clicked it.
799
- // Next we should hydrate C since that's the current hover target.
800
- // To simplify implementation details we hydrate both B and C at
801
- // the same time since B was already scheduled.
802
- // This is ok because it will at least not continue for nested
803
- // boundary. See the next test below.
804
- assertLog([
805
- 'D',
806
- 'Clicked D',
807
- 'B', // Ideally this should be later.
808
- 'C',
809
- 'Hover C',
810
- 'A',
811
- ]);
812
- }
715
+ // We should prioritize hydrating D first because we clicked it.
716
+ // but event isnt replayed
717
+ assertLog([
718
+ 'D',
719
+ 'B', // Ideally this should be later.
720
+ 'C',
721
+ 'Hover C',
722
+ 'A',
723
+ ]);
724
725
document.body.removeChild(container);
726
});
@@ -932,47 +843,22 @@ describe('ReactDOMServerSelectiveHydration', () => {
843
resolve();
844
});
845
935
- if (
936
- gate(
937
- flags =>
938
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
939
- )
940
- ) {
941
- // We should prioritize hydrating D first because we clicked it.
942
- // but event isnt replayed
943
- assertLog([
944
- 'D',
945
- 'B', // Ideally this should be later.
946
- 'C',
947
- // Mouse out events aren't replayed
948
- // 'Mouse Out Capture B',
949
- // 'Mouse Out B',
950
- 'Mouse Over Capture Parent',
951
- 'Mouse Over Capture C',
952
- // Stop propagation stops these
953
- // 'Mouse Over Capture Inner C',
954
- // 'Mouse Over C',
955
- 'A',
956
- ]);
957
- } else {
958
- // We should prioritize hydrating D first because we clicked it.
959
- // Next we should hydrate C since that's the current hover target.
960
- // To simplify implementation details we hydrate both B and C at
961
- // the same time since B was already scheduled.
962
- // This is ok because it will at least not continue for nested
963
- // boundary. See the next test below.
964
- assertLog([
965
- 'D',
966
- 'Clicked D',
967
- 'B', // Ideally this should be later.
968
- 'C',
969
- // Capture phase isn't replayed
970
- // Mouseout isn't replayed
971
- 'Mouse Over C',
972
- 'Mouse Enter C',
973
- 'A',
974
- ]);
975
- }
846
+ // We should prioritize hydrating D first because we clicked it.
847
+ // but event isnt replayed
848
+ assertLog([
849
+ 'D',
850
+ 'B', // Ideally this should be later.
851
+ 'C',
852
+ // Mouse out events aren't replayed
853
+ // 'Mouse Out Capture B',
854
+ // 'Mouse Out B',
855
+ 'Mouse Over Capture Parent',
856
+ 'Mouse Over Capture C',
857
+ // Stop propagation stops these
858
+ // 'Mouse Over Capture Inner C',
859
+ // 'Mouse Over C',
860
+ 'A',
861
+ ]);
862
863
// This test shows existing quirk where stopPropagation on mouseout
864
// prevents mouseEnter from firing
@@ -1129,19 +1015,10 @@ describe('ReactDOMServerSelectiveHydration', () => {
1015
});
1016
1017
OuterTestUtils.assertLog(['Suspend Outer']);
1132
- if (
1133
- gate(
1134
- flags =>
1135
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
1136
- )
1137
- ) {
1138
- // InnerApp doesn't see the event because OuterApp calls stopPropagation in
1139
- // capture phase since the event is blocked on suspended component
1140
- InnerTestUtils.assertLog([]);
1141
- } else {
1142
- // no stopPropagation
1143
- InnerTestUtils.assertLog(['Suspend Inner']);
1144
- }
1018
+
1019
+ // InnerApp doesn't see the event because OuterApp calls stopPropagation in
1020
+ // capture phase since the event is blocked on suspended component
1021
+ InnerTestUtils.assertLog([]);
1022
1023
assertLog([]);
1024
});
@@ -1149,7 +1026,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
1026
document.body.innerHTML = '';
1027
});
1028
1152
- // @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
1029
it('Inner hydrates first then Outer', async () => {
1030
dispatchMouseHoverEvent(innerDiv);
1031
@@ -1191,7 +1067,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
1067
assertLog(['Inner Mouse Enter', 'Outer Mouse Enter']);
1068
});
1069
1194
- // @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
1070
it('Outer hydrates first then Inner', async () => {
1071
dispatchMouseHoverEvent(innerDiv);
1072
@@ -1250,7 +1125,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
1125
});
1126
});
1127
1253
- // @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
1128
it('replays event with null target when tree is dismounted', async () => {
1129
let suspend = false;
1130
let resolve;
@@ -1565,7 +1439,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
1439
document.body.removeChild(container);
1440
});
1441
1568
- // @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
1442
it('fires capture event handlers and native events if content is hydratable during discrete event', async () => {
1443
spyOnDev(console, 'error');
1444
function Child({text}) {
@@ -1637,7 +1510,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
1510
document.body.removeChild(container);
1511
});
1512
1640
- // @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
1513
it('does not propagate discrete event if it cannot be synchronously hydrated', async () => {
1514
let triggeredParent = false;
1515
let triggeredChild = false;
@@ -1763,16 +1635,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
1635
});
1636
1637
// The app should have successfully hydrated and rendered
1766
- if (
1767
- gate(
1768
- flags =>
1769
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
1770
- )
1771
- ) {
1772
- assertLog(['App', 'A']);
1773
- } else {
1774
- assertLog(['App', 'A', 'Clicked A']);
1775
- }
1638
+ assertLog(['App', 'A']);
1639
1640
document.body.removeChild(container);
1641
});
packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js
+1
-12
@@ -666,18 +666,7 @@ describe('DOMPluginEventSystem', () => {
666
});
667
668
// We're now full hydrated.
669
-
670
- if (
671
- gate(
672
- flags =>
673
- flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
674
- )
675
- ) {
676
- expect(clicks).toBe(0);
677
- } else {
678
- expect(clicks).toBe(1);
679
- }
680
-
669
+ expect(clicks).toBe(0);
670
document.body.removeChild(parentContainer);
671
});
672
packages/react-reconciler/src/ReactFiberReconciler.js
-17
@@ -460,23 +460,6 @@ function markRetryLaneIfNotHydrated(fiber: Fiber, retryLane: Lane) {
460
}
461
}
462
463
-export function attemptDiscreteHydration(fiber: Fiber): void {
464
- if (fiber.tag !== SuspenseComponent) {
465
- // We ignore HostRoots here because we can't increase
466
- // their priority and they should not suspend on I/O,
467
- // since you have to wrap anything that might suspend in
468
- // Suspense.
469
- return;
470
- }
471
- const lane = SyncLane;
472
- const root = enqueueConcurrentRenderForLane(fiber, lane);
473
- if (root !== null) {
474
- const eventTime = requestEventTime();
475
- scheduleUpdateOnFiber(root, fiber, lane, eventTime);
476
- }
477
- markRetryLaneIfNotHydrated(fiber, lane);
478
-}
479
-
463
export function attemptContinuousHydration(fiber: Fiber): void {
464
if (fiber.tag !== SuspenseComponent) {
465
// We ignore HostRoots here because we can't increase
packages/shared/ReactFeatureFlags.js
-4
@@ -37,10 +37,6 @@ export const revertRemovalOfSiblingPrerendering = false;
37
// TODO: Finish rolling out in www
38
export const enableClientRenderFallbackOnTextMismatch = true;
39
40
-// TODO: Need to review this code one more time before landing
41
-export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
42
- true;
43
-
40
// Recoil still uses useMutableSource in www, need to delete
41
export const enableUseMutableSource = false;
42
packages/shared/forks/ReactFeatureFlags.native-fb.js
-2
@@ -52,8 +52,6 @@ export const enableCPUSuspense = true;
52
export const enableUseHook = true;
53
export const enableUseMemoCacheHook = true;
54
export const enableUseEffectEventHook = false;
55
-export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
56
- true;
55
export const enableClientRenderFallbackOnTextMismatch = true;
56
export const enableComponentStackLocations = false;
57
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.native-oss.js
-2
@@ -42,8 +42,6 @@ export const enableCPUSuspense = false;
42
export const enableUseHook = true;
43
export const enableUseMemoCacheHook = false;
44
export const enableUseEffectEventHook = false;
45
-export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
46
- true;
45
export const enableClientRenderFallbackOnTextMismatch = true;
46
export const enableComponentStackLocations = false;
47
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-2
@@ -42,8 +42,6 @@ export const enableCPUSuspense = false;
42
export const enableUseHook = true;
43
export const enableUseMemoCacheHook = false;
44
export const enableUseEffectEventHook = false;
45
-export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
46
- true;
45
export const enableClientRenderFallbackOnTextMismatch = true;
46
export const enableComponentStackLocations = true;
47
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
-2
@@ -46,8 +46,6 @@ export const enableCPUSuspense = false;
46
export const enableUseHook = true;
47
export const enableUseMemoCacheHook = false;
48
export const enableUseEffectEventHook = false;
49
-export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
50
- true;
49
export const enableClientRenderFallbackOnTextMismatch = true;
50
export const createRootStrictEffectsByDefault = false;
51
export const enableUseRefAccessWarning = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-2
@@ -42,8 +42,6 @@ export const enableCPUSuspense = false;
42
export const enableUseHook = true;
43
export const enableUseMemoCacheHook = false;
44
export const enableUseEffectEventHook = false;
45
-export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
46
- true;
45
export const enableClientRenderFallbackOnTextMismatch = true;
46
export const enableComponentStackLocations = true;
47
export const enableLegacyFBSupport = false;
packages/shared/forks/ReactFeatureFlags.www-dynamic.js
-2
@@ -21,8 +21,6 @@ export const enableProfilerNestedUpdateScheduledHook = __VARIANT__;
21
export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
22
export const enableLazyContextPropagation = __VARIANT__;
23
export const enableUnifiedSyncLane = __VARIANT__;
24
-export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
25
- __VARIANT__;
24
export const enableTransitionTracing = __VARIANT__;
25
export const enableCustomElementPropertySupport = __VARIANT__;
26
packages/shared/forks/ReactFeatureFlags.www.js
-1
@@ -25,7 +25,6 @@ export const {
25
enableUseRefAccessWarning,
26
enableLazyContextPropagation,
27
enableUnifiedSyncLane,
28
- enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
28
enableTransitionTracing,
29
enableCustomElementPropertySupport,
30
} = dynamicFeatureFlags;