Skip to content

Commit

Permalink
Clean up enableCapturePhaseSelectiveHydrationWithoutDiscreteEventRepl…
Browse files Browse the repository at this point in the history
…ay (#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.
  • Loading branch information
acdlite committed Mar 31, 2023
1 parent ca01f35 commit 8310854
Show file tree
Hide file tree
Showing 14 changed files with 74 additions and 546 deletions.
116 changes: 1 addition & 115 deletions packages/react-dom-bindings/src/events/ReactDOMEventListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand Down
130 changes: 10 additions & 120 deletions packages/react-dom-bindings/src/events/ReactDOMEventReplaying.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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';
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit 8310854

Please sign in to comment.