mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
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.
This commit is contained in:
+1
-115
@@ -12,11 +12,9 @@ import type {AnyNativeEvent} from '../events/PluginModuleType';
|
||||
import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
|
||||
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
|
||||
import type {DOMEventName} from '../events/DOMEventNames';
|
||||
import {enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay} from 'shared/ReactFeatureFlags';
|
||||
|
||||
import {
|
||||
isDiscreteEventThatRequiresHydration,
|
||||
queueDiscreteEvent,
|
||||
hasQueuedDiscreteEvents,
|
||||
clearIfContinuousEvent,
|
||||
queueIfContinuousEvent,
|
||||
} from './ReactDOMEventReplaying';
|
||||
@@ -156,119 +154,7 @@ export function dispatchEvent(
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
|
||||
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay(
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
nativeEvent,
|
||||
);
|
||||
} else {
|
||||
dispatchEventOriginal(
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
nativeEvent,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function dispatchEventOriginal(
|
||||
domEventName: DOMEventName,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
) {
|
||||
// TODO: replaying capture phase events is currently broken
|
||||
// because we used to do it during top-level native bubble handlers
|
||||
// but now we use different bubble and capture handlers.
|
||||
// In eager mode, we attach capture listeners early, so we need
|
||||
// to filter them out until we fix the logic to handle them correctly.
|
||||
const allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0;
|
||||
|
||||
if (
|
||||
allowReplay &&
|
||||
hasQueuedDiscreteEvents() &&
|
||||
isDiscreteEventThatRequiresHydration(domEventName)
|
||||
) {
|
||||
// If we already have a queue of discrete events, and this is another discrete
|
||||
// event, then we can't dispatch it regardless of its target, since they
|
||||
// need to dispatch in order.
|
||||
queueDiscreteEvent(
|
||||
null, // Flags that we're not actually blocked on anything as far as we know.
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
nativeEvent,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const blockedOn = findInstanceBlockingEvent(
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
nativeEvent,
|
||||
);
|
||||
if (blockedOn === null) {
|
||||
dispatchEventForPluginEventSystem(
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
nativeEvent,
|
||||
return_targetInst,
|
||||
targetContainer,
|
||||
);
|
||||
if (allowReplay) {
|
||||
clearIfContinuousEvent(domEventName, nativeEvent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (allowReplay) {
|
||||
if (isDiscreteEventThatRequiresHydration(domEventName)) {
|
||||
// This to be replayed later once the target is available.
|
||||
queueDiscreteEvent(
|
||||
blockedOn,
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
nativeEvent,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
queueIfContinuousEvent(
|
||||
blockedOn,
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
nativeEvent,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// We need to clear only if we didn't queue because
|
||||
// queueing is accumulative.
|
||||
clearIfContinuousEvent(domEventName, nativeEvent);
|
||||
}
|
||||
|
||||
// This is not replayable so we'll invoke it but without a target,
|
||||
// in case the event system needs to trace it.
|
||||
dispatchEventForPluginEventSystem(
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
nativeEvent,
|
||||
null,
|
||||
targetContainer,
|
||||
);
|
||||
}
|
||||
|
||||
function dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay(
|
||||
domEventName: DOMEventName,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
) {
|
||||
let blockedOn = findInstanceBlockingEvent(
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
|
||||
+10
-120
@@ -14,7 +14,6 @@ import type {EventSystemFlags} from './EventSystemFlags';
|
||||
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
|
||||
import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities';
|
||||
|
||||
import {enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay} from 'shared/ReactFeatureFlags';
|
||||
import {
|
||||
unstable_scheduleCallback as scheduleCallback,
|
||||
unstable_NormalPriority as NormalPriority,
|
||||
@@ -24,12 +23,8 @@ import {
|
||||
getContainerFromFiber,
|
||||
getSuspenseInstanceFromFiber,
|
||||
} from 'react-reconciler/src/ReactFiberTreeReflection';
|
||||
import {
|
||||
findInstanceBlockingEvent,
|
||||
return_targetInst,
|
||||
} from './ReactDOMEventListener';
|
||||
import {findInstanceBlockingEvent} from './ReactDOMEventListener';
|
||||
import {setReplayingEvent, resetReplayingEvent} from './CurrentReplayingEvent';
|
||||
import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
|
||||
import {
|
||||
getInstanceFromNode,
|
||||
getClosestInstanceFromNode,
|
||||
@@ -39,8 +34,6 @@ import {isHigherEventPriority} from 'react-reconciler/src/ReactEventPriorities';
|
||||
import {isRootDehydrated} from 'react-reconciler/src/ReactFiberShellHydration';
|
||||
|
||||
import {
|
||||
attemptSynchronousHydration,
|
||||
attemptDiscreteHydration,
|
||||
attemptContinuousHydration,
|
||||
attemptHydrationAtCurrentPriority,
|
||||
} from 'react-reconciler/src/ReactFiberReconciler';
|
||||
@@ -150,48 +143,6 @@ function createQueuedReplayableEvent(
|
||||
};
|
||||
}
|
||||
|
||||
export function queueDiscreteEvent(
|
||||
blockedOn: null | Container | SuspenseInstance,
|
||||
domEventName: DOMEventName,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
targetContainer: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
): void {
|
||||
if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
|
||||
return;
|
||||
}
|
||||
const queuedEvent = createQueuedReplayableEvent(
|
||||
blockedOn,
|
||||
domEventName,
|
||||
eventSystemFlags,
|
||||
targetContainer,
|
||||
nativeEvent,
|
||||
);
|
||||
queuedDiscreteEvents.push(queuedEvent);
|
||||
if (queuedDiscreteEvents.length === 1) {
|
||||
// If this was the first discrete event, we might be able to
|
||||
// synchronously unblock it so that preventDefault still works.
|
||||
while (queuedEvent.blockedOn !== null) {
|
||||
const fiber = getInstanceFromNode(queuedEvent.blockedOn);
|
||||
if (fiber === null) {
|
||||
break;
|
||||
}
|
||||
attemptSynchronousHydration(fiber);
|
||||
if (queuedEvent.blockedOn === null) {
|
||||
// We got unblocked by hydration. Let's try again.
|
||||
replayUnblockedEvents();
|
||||
// If we're reblocked, on an inner boundary, we might need
|
||||
// to attempt hydrating that one.
|
||||
continue;
|
||||
} else {
|
||||
// We're still blocked from hydration, we have to give up
|
||||
// and replay later.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resets the replaying for this type of continuous event to no event.
|
||||
export function clearIfContinuousEvent(
|
||||
domEventName: DOMEventName,
|
||||
@@ -433,26 +384,14 @@ function attemptReplayContinuousQueuedEvent(
|
||||
queuedEvent.nativeEvent,
|
||||
);
|
||||
if (nextBlockedOn === null) {
|
||||
if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
|
||||
const nativeEvent = queuedEvent.nativeEvent;
|
||||
const nativeEventClone = new nativeEvent.constructor(
|
||||
nativeEvent.type,
|
||||
(nativeEvent: any),
|
||||
);
|
||||
setReplayingEvent(nativeEventClone);
|
||||
nativeEvent.target.dispatchEvent(nativeEventClone);
|
||||
resetReplayingEvent();
|
||||
} else {
|
||||
setReplayingEvent(queuedEvent.nativeEvent);
|
||||
dispatchEventForPluginEventSystem(
|
||||
queuedEvent.domEventName,
|
||||
queuedEvent.eventSystemFlags,
|
||||
queuedEvent.nativeEvent,
|
||||
return_targetInst,
|
||||
targetContainer,
|
||||
);
|
||||
resetReplayingEvent();
|
||||
}
|
||||
const nativeEvent = queuedEvent.nativeEvent;
|
||||
const nativeEventClone = new nativeEvent.constructor(
|
||||
nativeEvent.type,
|
||||
(nativeEvent: any),
|
||||
);
|
||||
setReplayingEvent(nativeEventClone);
|
||||
nativeEvent.target.dispatchEvent(nativeEventClone);
|
||||
resetReplayingEvent();
|
||||
} else {
|
||||
// We're still blocked. Try again later.
|
||||
const fiber = getInstanceFromNode(nextBlockedOn);
|
||||
@@ -480,56 +419,7 @@ function attemptReplayContinuousQueuedEventInMap(
|
||||
|
||||
function replayUnblockedEvents() {
|
||||
hasScheduledReplayAttempt = false;
|
||||
if (!enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) {
|
||||
// First replay discrete events.
|
||||
while (queuedDiscreteEvents.length > 0) {
|
||||
const nextDiscreteEvent = queuedDiscreteEvents[0];
|
||||
if (nextDiscreteEvent.blockedOn !== null) {
|
||||
// We're still blocked.
|
||||
// Increase the priority of this boundary to unblock
|
||||
// the next discrete event.
|
||||
const fiber = getInstanceFromNode(nextDiscreteEvent.blockedOn);
|
||||
if (fiber !== null) {
|
||||
attemptDiscreteHydration(fiber);
|
||||
}
|
||||
break;
|
||||
}
|
||||
const targetContainers = nextDiscreteEvent.targetContainers;
|
||||
while (targetContainers.length > 0) {
|
||||
const targetContainer = targetContainers[0];
|
||||
const nextBlockedOn = findInstanceBlockingEvent(
|
||||
nextDiscreteEvent.domEventName,
|
||||
nextDiscreteEvent.eventSystemFlags,
|
||||
targetContainer,
|
||||
nextDiscreteEvent.nativeEvent,
|
||||
);
|
||||
if (nextBlockedOn === null) {
|
||||
// This whole function is in !enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
// so we don't need the new replay behavior code branch.
|
||||
setReplayingEvent(nextDiscreteEvent.nativeEvent);
|
||||
dispatchEventForPluginEventSystem(
|
||||
nextDiscreteEvent.domEventName,
|
||||
nextDiscreteEvent.eventSystemFlags,
|
||||
nextDiscreteEvent.nativeEvent,
|
||||
return_targetInst,
|
||||
targetContainer,
|
||||
);
|
||||
resetReplayingEvent();
|
||||
} else {
|
||||
// We're still blocked. Try again later.
|
||||
nextDiscreteEvent.blockedOn = nextBlockedOn;
|
||||
break;
|
||||
}
|
||||
// This target container was successfully dispatched. Try the next.
|
||||
targetContainers.shift();
|
||||
}
|
||||
if (nextDiscreteEvent.blockedOn === null) {
|
||||
// We've successfully replayed the first event. Let's try the next one.
|
||||
queuedDiscreteEvents.shift();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Next replay any continuous events.
|
||||
// Replay any continuous events.
|
||||
if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) {
|
||||
queuedFocus = null;
|
||||
}
|
||||
|
||||
@@ -2392,18 +2392,9 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
expect(clicks).toBe(0);
|
||||
expect(container.textContent).toBe('Click meHello');
|
||||
} else {
|
||||
expect(clicks).toBe(1);
|
||||
expect(container.textContent).toBe('Hello');
|
||||
}
|
||||
expect(clicks).toBe(0);
|
||||
expect(container.textContent).toBe('Click meHello');
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
@@ -2484,16 +2475,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
expect(onEvent).toHaveBeenCalledTimes(0);
|
||||
} else {
|
||||
expect(onEvent).toHaveBeenCalledTimes(2);
|
||||
}
|
||||
expect(onEvent).toHaveBeenCalledTimes(0);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -2573,16 +2555,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
expect(clicks).toBe(0);
|
||||
} else {
|
||||
expect(clicks).toBe(2);
|
||||
}
|
||||
expect(clicks).toBe(0);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -2666,16 +2639,8 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
resolve();
|
||||
await promise;
|
||||
});
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
expect(onEvent).toHaveBeenCalledTimes(0);
|
||||
} else {
|
||||
expect(onEvent).toHaveBeenCalledTimes(2);
|
||||
}
|
||||
|
||||
expect(onEvent).toHaveBeenCalledTimes(0);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -2746,19 +2711,8 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
expect(clicksOnChild).toBe(0);
|
||||
expect(clicksOnParent).toBe(0);
|
||||
} else {
|
||||
expect(clicksOnChild).toBe(1);
|
||||
// This will be zero due to the stopPropagation.
|
||||
expect(clicksOnParent).toBe(0);
|
||||
}
|
||||
expect(clicksOnChild).toBe(0);
|
||||
expect(clicksOnParent).toBe(0);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -2830,17 +2784,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
// We're now full hydrated.
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
expect(clicks).toBe(0);
|
||||
} else {
|
||||
expect(clicks).toBe(1);
|
||||
}
|
||||
expect(clicks).toBe(0);
|
||||
|
||||
document.body.removeChild(parentContainer);
|
||||
});
|
||||
@@ -3105,19 +3049,9 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
// discrete event not replayed
|
||||
expect(submits).toBe(0);
|
||||
expect(container.textContent).toBe('Click meHello');
|
||||
} else {
|
||||
expect(submits).toBe(1);
|
||||
expect(container.textContent).toBe('Hello');
|
||||
}
|
||||
// discrete event not replayed
|
||||
expect(submits).toBe(0);
|
||||
expect(container.textContent).toBe('Click meHello');
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
+49
-186
@@ -293,18 +293,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
assertLog(['D', 'A']);
|
||||
} else {
|
||||
// After the click, we should prioritize D and the Click first,
|
||||
// and only after that render A and C.
|
||||
assertLog(['D', 'Clicked D', 'A']);
|
||||
}
|
||||
assertLog(['D', 'A']);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -378,16 +367,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
dispatchClickEvent(spanC);
|
||||
dispatchClickEvent(spanD);
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
assertLog(['App', 'C', 'Clicked C']);
|
||||
} else {
|
||||
assertLog(['App']);
|
||||
}
|
||||
assertLog(['App', 'C', 'Clicked C']);
|
||||
|
||||
await act(async () => {
|
||||
suspend = false;
|
||||
@@ -395,29 +375,12 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
ReactFeatureFlags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
) {
|
||||
assertLog([
|
||||
'A',
|
||||
'D',
|
||||
// B should render last since it wasn't clicked.
|
||||
'B',
|
||||
]);
|
||||
} else {
|
||||
// We should prioritize hydrating A, C and D first since we clicked in
|
||||
// them. Only after they're done will we hydrate B.
|
||||
assertLog([
|
||||
'A',
|
||||
'Clicked A',
|
||||
'C',
|
||||
'Clicked C',
|
||||
'D',
|
||||
'Clicked D',
|
||||
// B should render last since it wasn't clicked.
|
||||
'B',
|
||||
]);
|
||||
}
|
||||
assertLog([
|
||||
'A',
|
||||
'D',
|
||||
// B should render last since it wasn't clicked.
|
||||
'B',
|
||||
]);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -571,17 +534,9 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
resolve();
|
||||
await promise;
|
||||
});
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
// no replay
|
||||
assertLog(['D', 'A']);
|
||||
} else {
|
||||
assertLog(['D', 'Clicked D', 'A']);
|
||||
}
|
||||
|
||||
// no replay
|
||||
assertLog(['D', 'A']);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -660,42 +615,20 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
createEventTarget(spanC).virtualclick();
|
||||
createEventTarget(spanD).virtualclick();
|
||||
|
||||
if (
|
||||
ReactFeatureFlags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
) {
|
||||
assertLog(['App', 'C', 'Clicked C']);
|
||||
} else {
|
||||
assertLog(['App']);
|
||||
}
|
||||
assertLog(['App', 'C', 'Clicked C']);
|
||||
|
||||
await act(async () => {
|
||||
suspend = false;
|
||||
resolve();
|
||||
await promise;
|
||||
});
|
||||
|
||||
if (
|
||||
ReactFeatureFlags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
) {
|
||||
assertLog([
|
||||
'A',
|
||||
'D',
|
||||
// B should render last since it wasn't clicked.
|
||||
'B',
|
||||
]);
|
||||
} else {
|
||||
// We should prioritize hydrating A, C and D first since we clicked in
|
||||
// them. Only after they're done will we hydrate B.
|
||||
assertLog([
|
||||
'A',
|
||||
'Clicked A',
|
||||
'C',
|
||||
'Clicked C',
|
||||
'D',
|
||||
'Clicked D',
|
||||
// B should render last since it wasn't clicked.
|
||||
'B',
|
||||
]);
|
||||
}
|
||||
assertLog([
|
||||
'A',
|
||||
'D',
|
||||
// B should render last since it wasn't clicked.
|
||||
'B',
|
||||
]);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -779,37 +712,15 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
// We should prioritize hydrating D first because we clicked it.
|
||||
// but event isnt replayed
|
||||
assertLog([
|
||||
'D',
|
||||
'B', // Ideally this should be later.
|
||||
'C',
|
||||
'Hover C',
|
||||
'A',
|
||||
]);
|
||||
} else {
|
||||
// We should prioritize hydrating D first because we clicked it.
|
||||
// Next we should hydrate C since that's the current hover target.
|
||||
// To simplify implementation details we hydrate both B and C at
|
||||
// the same time since B was already scheduled.
|
||||
// This is ok because it will at least not continue for nested
|
||||
// boundary. See the next test below.
|
||||
assertLog([
|
||||
'D',
|
||||
'Clicked D',
|
||||
'B', // Ideally this should be later.
|
||||
'C',
|
||||
'Hover C',
|
||||
'A',
|
||||
]);
|
||||
}
|
||||
// We should prioritize hydrating D first because we clicked it.
|
||||
// but event isnt replayed
|
||||
assertLog([
|
||||
'D',
|
||||
'B', // Ideally this should be later.
|
||||
'C',
|
||||
'Hover C',
|
||||
'A',
|
||||
]);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
@@ -932,47 +843,22 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
// We should prioritize hydrating D first because we clicked it.
|
||||
// but event isnt replayed
|
||||
assertLog([
|
||||
'D',
|
||||
'B', // Ideally this should be later.
|
||||
'C',
|
||||
// Mouse out events aren't replayed
|
||||
// 'Mouse Out Capture B',
|
||||
// 'Mouse Out B',
|
||||
'Mouse Over Capture Parent',
|
||||
'Mouse Over Capture C',
|
||||
// Stop propagation stops these
|
||||
// 'Mouse Over Capture Inner C',
|
||||
// 'Mouse Over C',
|
||||
'A',
|
||||
]);
|
||||
} else {
|
||||
// We should prioritize hydrating D first because we clicked it.
|
||||
// Next we should hydrate C since that's the current hover target.
|
||||
// To simplify implementation details we hydrate both B and C at
|
||||
// the same time since B was already scheduled.
|
||||
// This is ok because it will at least not continue for nested
|
||||
// boundary. See the next test below.
|
||||
assertLog([
|
||||
'D',
|
||||
'Clicked D',
|
||||
'B', // Ideally this should be later.
|
||||
'C',
|
||||
// Capture phase isn't replayed
|
||||
// Mouseout isn't replayed
|
||||
'Mouse Over C',
|
||||
'Mouse Enter C',
|
||||
'A',
|
||||
]);
|
||||
}
|
||||
// We should prioritize hydrating D first because we clicked it.
|
||||
// but event isnt replayed
|
||||
assertLog([
|
||||
'D',
|
||||
'B', // Ideally this should be later.
|
||||
'C',
|
||||
// Mouse out events aren't replayed
|
||||
// 'Mouse Out Capture B',
|
||||
// 'Mouse Out B',
|
||||
'Mouse Over Capture Parent',
|
||||
'Mouse Over Capture C',
|
||||
// Stop propagation stops these
|
||||
// 'Mouse Over Capture Inner C',
|
||||
// 'Mouse Over C',
|
||||
'A',
|
||||
]);
|
||||
|
||||
// This test shows existing quirk where stopPropagation on mouseout
|
||||
// prevents mouseEnter from firing
|
||||
@@ -1129,19 +1015,10 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
});
|
||||
|
||||
OuterTestUtils.assertLog(['Suspend Outer']);
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
// InnerApp doesn't see the event because OuterApp calls stopPropagation in
|
||||
// capture phase since the event is blocked on suspended component
|
||||
InnerTestUtils.assertLog([]);
|
||||
} else {
|
||||
// no stopPropagation
|
||||
InnerTestUtils.assertLog(['Suspend Inner']);
|
||||
}
|
||||
|
||||
// InnerApp doesn't see the event because OuterApp calls stopPropagation in
|
||||
// capture phase since the event is blocked on suspended component
|
||||
InnerTestUtils.assertLog([]);
|
||||
|
||||
assertLog([]);
|
||||
});
|
||||
@@ -1149,7 +1026,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
// @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
it('Inner hydrates first then Outer', async () => {
|
||||
dispatchMouseHoverEvent(innerDiv);
|
||||
|
||||
@@ -1191,7 +1067,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
assertLog(['Inner Mouse Enter', 'Outer Mouse Enter']);
|
||||
});
|
||||
|
||||
// @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
it('Outer hydrates first then Inner', async () => {
|
||||
dispatchMouseHoverEvent(innerDiv);
|
||||
|
||||
@@ -1250,7 +1125,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
it('replays event with null target when tree is dismounted', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
@@ -1565,7 +1439,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
it('fires capture event handlers and native events if content is hydratable during discrete event', async () => {
|
||||
spyOnDev(console, 'error');
|
||||
function Child({text}) {
|
||||
@@ -1637,7 +1510,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay
|
||||
it('does not propagate discrete event if it cannot be synchronously hydrated', async () => {
|
||||
let triggeredParent = false;
|
||||
let triggeredChild = false;
|
||||
@@ -1763,16 +1635,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
});
|
||||
|
||||
// The app should have successfully hydrated and rendered
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
assertLog(['App', 'A']);
|
||||
} else {
|
||||
assertLog(['App', 'A', 'Clicked A']);
|
||||
}
|
||||
assertLog(['App', 'A']);
|
||||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
@@ -666,18 +666,7 @@ describe('DOMPluginEventSystem', () => {
|
||||
});
|
||||
|
||||
// We're now full hydrated.
|
||||
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
flags.enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
)
|
||||
) {
|
||||
expect(clicks).toBe(0);
|
||||
} else {
|
||||
expect(clicks).toBe(1);
|
||||
}
|
||||
|
||||
expect(clicks).toBe(0);
|
||||
document.body.removeChild(parentContainer);
|
||||
});
|
||||
|
||||
|
||||
@@ -460,23 +460,6 @@ function markRetryLaneIfNotHydrated(fiber: Fiber, retryLane: Lane) {
|
||||
}
|
||||
}
|
||||
|
||||
export function attemptDiscreteHydration(fiber: Fiber): void {
|
||||
if (fiber.tag !== SuspenseComponent) {
|
||||
// We ignore HostRoots here because we can't increase
|
||||
// their priority and they should not suspend on I/O,
|
||||
// since you have to wrap anything that might suspend in
|
||||
// Suspense.
|
||||
return;
|
||||
}
|
||||
const lane = SyncLane;
|
||||
const root = enqueueConcurrentRenderForLane(fiber, lane);
|
||||
if (root !== null) {
|
||||
const eventTime = requestEventTime();
|
||||
scheduleUpdateOnFiber(root, fiber, lane, eventTime);
|
||||
}
|
||||
markRetryLaneIfNotHydrated(fiber, lane);
|
||||
}
|
||||
|
||||
export function attemptContinuousHydration(fiber: Fiber): void {
|
||||
if (fiber.tag !== SuspenseComponent) {
|
||||
// We ignore HostRoots here because we can't increase
|
||||
|
||||
@@ -37,10 +37,6 @@ export const revertRemovalOfSiblingPrerendering = false;
|
||||
// TODO: Finish rolling out in www
|
||||
export const enableClientRenderFallbackOnTextMismatch = true;
|
||||
|
||||
// TODO: Need to review this code one more time before landing
|
||||
export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
|
||||
true;
|
||||
|
||||
// Recoil still uses useMutableSource in www, need to delete
|
||||
export const enableUseMutableSource = false;
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ export const enableCPUSuspense = true;
|
||||
export const enableUseHook = true;
|
||||
export const enableUseMemoCacheHook = true;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
|
||||
true;
|
||||
export const enableClientRenderFallbackOnTextMismatch = true;
|
||||
export const enableComponentStackLocations = false;
|
||||
export const enableLegacyFBSupport = false;
|
||||
|
||||
@@ -42,8 +42,6 @@ export const enableCPUSuspense = false;
|
||||
export const enableUseHook = true;
|
||||
export const enableUseMemoCacheHook = false;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
|
||||
true;
|
||||
export const enableClientRenderFallbackOnTextMismatch = true;
|
||||
export const enableComponentStackLocations = false;
|
||||
export const enableLegacyFBSupport = false;
|
||||
|
||||
@@ -42,8 +42,6 @@ export const enableCPUSuspense = false;
|
||||
export const enableUseHook = true;
|
||||
export const enableUseMemoCacheHook = false;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
|
||||
true;
|
||||
export const enableClientRenderFallbackOnTextMismatch = true;
|
||||
export const enableComponentStackLocations = true;
|
||||
export const enableLegacyFBSupport = false;
|
||||
|
||||
@@ -46,8 +46,6 @@ export const enableCPUSuspense = false;
|
||||
export const enableUseHook = true;
|
||||
export const enableUseMemoCacheHook = false;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
|
||||
true;
|
||||
export const enableClientRenderFallbackOnTextMismatch = true;
|
||||
export const createRootStrictEffectsByDefault = false;
|
||||
export const enableUseRefAccessWarning = false;
|
||||
|
||||
@@ -42,8 +42,6 @@ export const enableCPUSuspense = false;
|
||||
export const enableUseHook = true;
|
||||
export const enableUseMemoCacheHook = false;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
|
||||
true;
|
||||
export const enableClientRenderFallbackOnTextMismatch = true;
|
||||
export const enableComponentStackLocations = true;
|
||||
export const enableLegacyFBSupport = false;
|
||||
|
||||
@@ -21,8 +21,6 @@ export const enableProfilerNestedUpdateScheduledHook = __VARIANT__;
|
||||
export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
|
||||
export const enableLazyContextPropagation = __VARIANT__;
|
||||
export const enableUnifiedSyncLane = __VARIANT__;
|
||||
export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay =
|
||||
__VARIANT__;
|
||||
export const enableTransitionTracing = __VARIANT__;
|
||||
export const enableCustomElementPropertySupport = __VARIANT__;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ export const {
|
||||
enableUseRefAccessWarning,
|
||||
enableLazyContextPropagation,
|
||||
enableUnifiedSyncLane,
|
||||
enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay,
|
||||
enableTransitionTracing,
|
||||
enableCustomElementPropertySupport,
|
||||
} = dynamicFeatureFlags;
|
||||
|
||||
Reference in New Issue
Block a user