@@ -12,7 +12,10 @@ import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
1212import type { DOMTopLevelEventType } from 'legacy-events/TopLevelEventTypes' ;
1313import type { EventSystemFlags } from 'legacy-events/EventSystemFlags' ;
1414
15- import { enableFlareAPI } from 'shared/ReactFeatureFlags' ;
15+ import {
16+ enableFlareAPI ,
17+ enableSelectiveHydration ,
18+ } from 'shared/ReactFeatureFlags' ;
1619import {
1720 unstable_scheduleCallback as scheduleCallback ,
1821 unstable_NormalPriority as NormalPriority ,
@@ -25,8 +28,15 @@ import {
2528 getListeningSetForElement ,
2629 listenToTopLevel ,
2730} from './ReactBrowserEventEmitter' ;
31+ import { getInstanceFromNode } from '../client/ReactDOMComponentTree' ;
2832import { unsafeCastDOMTopLevelTypeToString } from 'legacy-events/TopLevelEventTypes' ;
2933
34+ let attemptSynchronousHydration : ( fiber : Object ) => void ;
35+
36+ export function setAttemptSynchronousHydration ( fn : ( fiber : Object ) = > void ) {
37+ attemptSynchronousHydration = fn ;
38+ }
39+
3040// TODO: Upgrade this definition once we're on a newer version of Flow that
3141// has this definition built-in.
3242type PointerEvent = Event & {
@@ -223,18 +233,36 @@ export function queueDiscreteEvent(
223233 eventSystemFlags : EventSystemFlags ,
224234 nativeEvent : AnyNativeEvent ,
225235) : void {
226- queuedDiscreteEvents . push (
227- createQueuedReplayableEvent (
228- blockedOn ,
229- topLevelType ,
230- eventSystemFlags ,
231- nativeEvent ,
232- ) ,
236+ const queuedEvent = createQueuedReplayableEvent (
237+ blockedOn ,
238+ topLevelType ,
239+ eventSystemFlags ,
240+ nativeEvent ,
233241 ) ;
234- if ( blockedOn === null && queuedDiscreteEvents . length === 1 ) {
235- // This probably shouldn't happen but some defensive coding might
236- // help us get unblocked if we have a bug.
237- replayUnblockedEvents ( ) ;
242+ queuedDiscreteEvents . push ( queuedEvent ) ;
243+ if ( enableSelectiveHydration ) {
244+ if ( queuedDiscreteEvents . length === 1 ) {
245+ // If this was the first discrete event, we might be able to
246+ // synchronously unblock it so that preventDefault still works.
247+ while ( queuedEvent . blockedOn !== null ) {
248+ let fiber = getInstanceFromNode ( queuedEvent . blockedOn ) ;
249+ if ( fiber === null ) {
250+ break ;
251+ }
252+ attemptSynchronousHydration ( fiber ) ;
253+ if ( queuedEvent . blockedOn === null ) {
254+ // We got unblocked by hydration. Let's try again.
255+ replayUnblockedEvents ( ) ;
256+ // If we're reblocked, on an inner boundary, we might need
257+ // to attempt hydrating that one.
258+ continue ;
259+ } else {
260+ // We're still blocked from hydation, we have to give up
261+ // and replay later.
262+ break ;
263+ }
264+ }
265+ }
238266 }
239267}
240268
0 commit comments