Skip to content

Commit b59876d

Browse files
gaearonsalazarm
authored andcommitted
Track currently replaying event (facebook#22853)
* Track currently replaying event Co-authored-by: Dan Abramov <[email protected]> * Add warnings Co-authored-by: Marco Salazar <[email protected]>
1 parent 493a2f0 commit b59876d

File tree

5 files changed

+55
-9
lines changed

5 files changed

+55
-9
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
import type {AnyNativeEvent} from '../events/PluginModuleType';
10+
11+
// This exists to avoid circular dependency between ReactDOMEventReplaying
12+
// and DOMPluginEventSystem.
13+
14+
let currentReplayingEvent = null;
15+
16+
export function setReplayingEvent(event: AnyNativeEvent): void {
17+
if (__DEV__) {
18+
if (currentReplayingEvent !== null) {
19+
console.error(
20+
'Expected currently replaying event to be null. This error ' +
21+
'is likely caused by a bug in React. Please file an issue.',
22+
);
23+
}
24+
}
25+
currentReplayingEvent = event;
26+
}
27+
28+
export function resetReplayingEvent(): void {
29+
if (__DEV__) {
30+
if (currentReplayingEvent === null) {
31+
console.error(
32+
'Expected currently replaying event to not be null. This error ' +
33+
'is likely caused by a bug in React. Please file an issue.',
34+
);
35+
}
36+
}
37+
currentReplayingEvent = null;
38+
}
39+
40+
export function isReplayingEvent(event: AnyNativeEvent): boolean {
41+
return event === currentReplayingEvent;
42+
}

packages/react-dom/src/events/DOMPluginEventSystem.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
IS_EVENT_HANDLE_NON_MANAGED_NODE,
2828
IS_NON_DELEGATED,
2929
} from './EventSystemFlags';
30+
import {isReplayingEvent} from './CurrentReplayingEvent';
3031

3132
import {
3233
HostRoot,
@@ -557,7 +558,8 @@ export function dispatchEventForPluginEventSystem(
557558
// for legacy FB support, where the expected behavior was to
558559
// match React < 16 behavior of delegated clicks to the doc.
559560
domEventName === 'click' &&
560-
(eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0
561+
(eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0 &&
562+
!isReplayingEvent(nativeEvent)
561563
) {
562564
deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer);
563565
return;

packages/react-dom/src/events/EventSystemFlags.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@ export const IS_EVENT_HANDLE_NON_MANAGED_NODE = 1;
1313
export const IS_NON_DELEGATED = 1 << 1;
1414
export const IS_CAPTURE_PHASE = 1 << 2;
1515
export const IS_PASSIVE = 1 << 3;
16-
export const IS_REPLAYED = 1 << 4;
17-
export const IS_LEGACY_FB_SUPPORT_MODE = 1 << 5;
16+
export const IS_LEGACY_FB_SUPPORT_MODE = 1 << 4;
1817

1918
export const SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE =
20-
IS_LEGACY_FB_SUPPORT_MODE | IS_REPLAYED | IS_CAPTURE_PHASE;
19+
IS_LEGACY_FB_SUPPORT_MODE | IS_CAPTURE_PHASE;
2120

2221
// We do not want to defer if the event system has already been
2322
// set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when

packages/react-dom/src/events/ReactDOMEventReplaying.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
findInstanceBlockingEvent,
3232
return_targetInst,
3333
} from './ReactDOMEventListener';
34+
import {setReplayingEvent, resetReplayingEvent} from './CurrentReplayingEvent';
3435
import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
3536
import {
3637
getInstanceFromNode,
@@ -91,8 +92,6 @@ type PointerEvent = Event & {
9192
...
9293
};
9394

94-
import {IS_REPLAYED} from './EventSystemFlags';
95-
9695
type QueuedReplayableEvent = {|
9796
blockedOn: null | Container | SuspenseInstance,
9897
domEventName: DOMEventName,
@@ -180,7 +179,7 @@ function createQueuedReplayableEvent(
180179
return {
181180
blockedOn,
182181
domEventName,
183-
eventSystemFlags: eventSystemFlags | IS_REPLAYED,
182+
eventSystemFlags,
184183
nativeEvent,
185184
targetContainers: [targetContainer],
186185
};
@@ -473,13 +472,15 @@ function attemptReplayContinuousQueuedEvent(
473472
queuedEvent.nativeEvent,
474473
);
475474
if (nextBlockedOn === null) {
475+
setReplayingEvent(queuedEvent.nativeEvent);
476476
dispatchEventForPluginEventSystem(
477477
queuedEvent.domEventName,
478478
queuedEvent.eventSystemFlags,
479479
queuedEvent.nativeEvent,
480480
return_targetInst,
481481
targetContainer,
482482
);
483+
resetReplayingEvent();
483484
} else {
484485
// We're still blocked. Try again later.
485486
const fiber = getInstanceFromNode(nextBlockedOn);
@@ -531,13 +532,15 @@ function replayUnblockedEvents() {
531532
nextDiscreteEvent.nativeEvent,
532533
);
533534
if (nextBlockedOn === null) {
535+
setReplayingEvent(nextDiscreteEvent.nativeEvent);
534536
dispatchEventForPluginEventSystem(
535537
nextDiscreteEvent.domEventName,
536538
nextDiscreteEvent.eventSystemFlags,
537539
nextDiscreteEvent.nativeEvent,
538540
return_targetInst,
539541
targetContainer,
540542
);
543+
resetReplayingEvent();
541544
} else {
542545
// We're still blocked. Try again later.
543546
nextDiscreteEvent.blockedOn = nextBlockedOn;

packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {DispatchQueue} from '../DOMPluginEventSystem';
1313
import type {EventSystemFlags} from '../EventSystemFlags';
1414

1515
import {registerDirectEvent} from '../EventRegistry';
16-
import {IS_REPLAYED} from 'react-dom/src/events/EventSystemFlags';
16+
import {isReplayingEvent} from '../CurrentReplayingEvent';
1717
import {SyntheticMouseEvent, SyntheticPointerEvent} from '../SyntheticEvent';
1818
import {
1919
getClosestInstanceFromNode,
@@ -54,7 +54,7 @@ function extractEvents(
5454
const isOutEvent =
5555
domEventName === 'mouseout' || domEventName === 'pointerout';
5656

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

0 commit comments

Comments
 (0)