Skip to content

Commit

Permalink
Track currently replaying event
Browse files Browse the repository at this point in the history
Co-authored-by: Dan Abramov <[email protected]>
  • Loading branch information
salazarm and gaearon committed Dec 2, 2021
1 parent 2e1ddc2 commit 06d85b0
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 9 deletions.
26 changes: 26 additions & 0 deletions packages/react-dom/src/events/CurrentReplayingEvent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {AnyNativeEvent} from '../events/PluginModuleType';

// This exists to avoid circular dependency between ReactDOMEventReplaying
// and DOMPluginEventSystem.

let currentReplayingEvent = null;

export function setReplayingEvent(event: AnyNativeEvent): void {
currentReplayingEvent = event;
}

export function resetReplayingEvent(): void {
currentReplayingEvent = null;
}

export function isReplayingEvent(event: AnyNativeEvent): boolean {
return event === currentReplayingEvent;
}
4 changes: 3 additions & 1 deletion packages/react-dom/src/events/DOMPluginEventSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
IS_EVENT_HANDLE_NON_MANAGED_NODE,
IS_NON_DELEGATED,
} from './EventSystemFlags';
import {isReplayingEvent} from './CurrentReplayingEvent';

import {
HostRoot,
Expand Down Expand Up @@ -557,7 +558,8 @@ export function dispatchEventForPluginEventSystem(
// for legacy FB support, where the expected behavior was to
// match React < 16 behavior of delegated clicks to the doc.
domEventName === 'click' &&
(eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0
(eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0 &&
!isReplayingEvent(nativeEvent)
) {
deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer);
return;
Expand Down
5 changes: 2 additions & 3 deletions packages/react-dom/src/events/EventSystemFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ export const IS_EVENT_HANDLE_NON_MANAGED_NODE = 1;
export const IS_NON_DELEGATED = 1 << 1;
export const IS_CAPTURE_PHASE = 1 << 2;
export const IS_PASSIVE = 1 << 3;
export const IS_REPLAYED = 1 << 4;
export const IS_LEGACY_FB_SUPPORT_MODE = 1 << 5;
export const IS_LEGACY_FB_SUPPORT_MODE = 1 << 4;

export const SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE =
IS_LEGACY_FB_SUPPORT_MODE | IS_REPLAYED | IS_CAPTURE_PHASE;
IS_LEGACY_FB_SUPPORT_MODE | IS_CAPTURE_PHASE;

// We do not want to defer if the event system has already been
// set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when
Expand Down
9 changes: 6 additions & 3 deletions packages/react-dom/src/events/ReactDOMEventReplaying.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
return_targetInst,
return_shouldDispatch,
} from './ReactDOMEventListener';
import {setReplayingEvent, resetReplayingEvent} from './CurrentReplayingEvent';
import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
import {
getInstanceFromNode,
Expand Down Expand Up @@ -92,8 +93,6 @@ type PointerEvent = Event & {
...
};

import {IS_REPLAYED} from './EventSystemFlags';

type QueuedReplayableEvent = {|
blockedOn: null | Container | SuspenseInstance,
domEventName: DOMEventName,
Expand Down Expand Up @@ -181,7 +180,7 @@ function createQueuedReplayableEvent(
return {
blockedOn,
domEventName,
eventSystemFlags: eventSystemFlags | IS_REPLAYED,
eventSystemFlags,
nativeEvent,
targetContainers: [targetContainer],
};
Expand Down Expand Up @@ -474,13 +473,15 @@ function attemptReplayContinuousQueuedEvent(
queuedEvent.nativeEvent,
);
if (return_shouldDispatch) {
setReplayingEvent(queuedEvent.nativeEvent);
dispatchEventForPluginEventSystem(
queuedEvent.domEventName,
queuedEvent.eventSystemFlags,
queuedEvent.nativeEvent,
return_targetInst,
targetContainer,
);
resetReplayingEvent();
}
if (nextBlockedOn !== null) {
// We're still blocked. Try again later.
Expand Down Expand Up @@ -533,13 +534,15 @@ function replayUnblockedEvents() {
nextDiscreteEvent.nativeEvent,
);
if (return_shouldDispatch) {
setReplayingEvent(nextDiscreteEvent.nativeEvent);
dispatchEventForPluginEventSystem(
nextDiscreteEvent.domEventName,
nextDiscreteEvent.eventSystemFlags,
nextDiscreteEvent.nativeEvent,
return_targetInst,
targetContainer,
);
resetReplayingEvent();
}
if (nextBlockedOn !== null) {
// We're still blocked. Try again later.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type {DispatchQueue} from '../DOMPluginEventSystem';
import type {EventSystemFlags} from '../EventSystemFlags';

import {registerDirectEvent} from '../EventRegistry';
import {IS_REPLAYED} from 'react-dom/src/events/EventSystemFlags';
import {isReplayingEvent} from '../CurrentReplayingEvent';
import {SyntheticMouseEvent, SyntheticPointerEvent} from '../SyntheticEvent';
import {
getClosestInstanceFromNode,
Expand Down Expand Up @@ -54,7 +54,7 @@ function extractEvents(
const isOutEvent =
domEventName === 'mouseout' || domEventName === 'pointerout';

if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
if (isOverEvent && !isReplayingEvent(nativeEvent)) {
// If this is an over event with a target, we might have already dispatched
// the event in the out event of the other target. If this is replayed,
// then it's because we couldn't dispatch against this target previously
Expand Down

0 comments on commit 06d85b0

Please sign in to comment.