@samitouri / QOS-React-2 / commits / 8310854ceb

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;