Skip to content

Commit

Permalink
Track currently replaying event (#22853)
Browse files Browse the repository at this point in the history
* Track currently replaying event

Co-authored-by: Dan Abramov <[email protected]>

* Add warnings

Co-authored-by: Marco Salazar <[email protected]>
  • Loading branch information
gaearon and salazarm authored Dec 2, 2021
1 parent e737ea9 commit 44f99d7
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 9 deletions.
42 changes: 42 additions & 0 deletions packages/react-dom/src/events/CurrentReplayingEvent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* 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 {
if (__DEV__) {
if (currentReplayingEvent !== null) {
console.error(
'Expected currently replaying event to be null. This error ' +
'is likely caused by a bug in React. Please file an issue.',
);
}
}
currentReplayingEvent = event;
}

export function resetReplayingEvent(): void {
if (__DEV__) {
if (currentReplayingEvent === null) {
console.error(
'Expected currently replaying event to not be null. This error ' +
'is likely caused by a bug in React. Please file an issue.',
);
}
}
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 @@ -31,6 +31,7 @@ import {
findInstanceBlockingEvent,
return_targetInst,
} from './ReactDOMEventListener';
import {setReplayingEvent, resetReplayingEvent} from './CurrentReplayingEvent';
import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
import {
getInstanceFromNode,
Expand Down Expand Up @@ -91,8 +92,6 @@ type PointerEvent = Event & {
...
};

import {IS_REPLAYED} from './EventSystemFlags';

type QueuedReplayableEvent = {|
blockedOn: null | Container | SuspenseInstance,
domEventName: DOMEventName,
Expand Down Expand Up @@ -180,7 +179,7 @@ function createQueuedReplayableEvent(
return {
blockedOn,
domEventName,
eventSystemFlags: eventSystemFlags | IS_REPLAYED,
eventSystemFlags,
nativeEvent,
targetContainers: [targetContainer],
};
Expand Down Expand Up @@ -473,13 +472,15 @@ function attemptReplayContinuousQueuedEvent(
queuedEvent.nativeEvent,
);
if (nextBlockedOn === null) {
setReplayingEvent(queuedEvent.nativeEvent);
dispatchEventForPluginEventSystem(
queuedEvent.domEventName,
queuedEvent.eventSystemFlags,
queuedEvent.nativeEvent,
return_targetInst,
targetContainer,
);
resetReplayingEvent();
} else {
// We're still blocked. Try again later.
const fiber = getInstanceFromNode(nextBlockedOn);
Expand Down Expand Up @@ -531,13 +532,15 @@ function replayUnblockedEvents() {
nextDiscreteEvent.nativeEvent,
);
if (nextBlockedOn === null) {
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;
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 44f99d7

Please sign in to comment.