@samitouri / QOS-React-2 / commits / 44f99d75fa

Track currently replaying event (#22853)

* Track currently replaying event Co-authored-by: Dan Abramov <dan.abramov@me.com> * Add warnings Co-authored-by: Marco Salazar <salazarm@fb.com>

Dan Abramov committed Dec 2, 2021 at 14:11 UTC 44f99d75fa4528b82810edd03eccf82f7ea21ea0
5 files changed +55 -9
packages/react-dom/src/events/CurrentReplayingEvent.js new
+42
@@ -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
+3 -1
@@ -27,6 +27,7 @@ import {
27 IS_EVENT_HANDLE_NON_MANAGED_NODE,
28 IS_NON_DELEGATED,
29 } from './EventSystemFlags';
30 +import {isReplayingEvent} from './CurrentReplayingEvent';
31
32 import {
33 HostRoot,
@@ -557,7 +558,8 @@ export function dispatchEventForPluginEventSystem(
558 // for legacy FB support, where the expected behavior was to
559 // match React < 16 behavior of delegated clicks to the doc.
560 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)
563 ) {
564 deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer);
565 return;
packages/react-dom/src/events/EventSystemFlags.js
+2 -3
@@ -13,11 +13,10 @@ export const IS_EVENT_HANDLE_NON_MANAGED_NODE = 1;
13 export const IS_NON_DELEGATED = 1 << 1;
14 export const IS_CAPTURE_PHASE = 1 << 2;
15 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;
17
18 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;
20
21 // We do not want to defer if the event system has already been
22 // set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when
packages/react-dom/src/events/ReactDOMEventReplaying.js
+6 -3
@@ -31,6 +31,7 @@ import {
31 findInstanceBlockingEvent,
32 return_targetInst,
33 } from './ReactDOMEventListener';
34 +import {setReplayingEvent, resetReplayingEvent} from './CurrentReplayingEvent';
35 import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
36 import {
37 getInstanceFromNode,
@@ -91,8 +92,6 @@ type PointerEvent = Event & {
92 ...
93 };
94
94 -import {IS_REPLAYED} from './EventSystemFlags';
95 -
95 type QueuedReplayableEvent = {|
96 blockedOn: null | Container | SuspenseInstance,
97 domEventName: DOMEventName,
@@ -180,7 +179,7 @@ function createQueuedReplayableEvent(
179 return {
180 blockedOn,
181 domEventName,
183 - eventSystemFlags: eventSystemFlags | IS_REPLAYED,
182 + eventSystemFlags,
183 nativeEvent,
184 targetContainers: [targetContainer],
185 };
@@ -473,6 +472,7 @@ function attemptReplayContinuousQueuedEvent(
472 queuedEvent.nativeEvent,
473 );
474 if (nextBlockedOn === null) {
475 + setReplayingEvent(queuedEvent.nativeEvent);
476 dispatchEventForPluginEventSystem(
477 queuedEvent.domEventName,
478 queuedEvent.eventSystemFlags,
@@ -480,6 +480,7 @@ function attemptReplayContinuousQueuedEvent(
480 return_targetInst,
481 targetContainer,
482 );
483 + resetReplayingEvent();
484 } else {
485 // We're still blocked. Try again later.
486 const fiber = getInstanceFromNode(nextBlockedOn);
@@ -531,6 +532,7 @@ function replayUnblockedEvents() {
532 nextDiscreteEvent.nativeEvent,
533 );
534 if (nextBlockedOn === null) {
535 + setReplayingEvent(nextDiscreteEvent.nativeEvent);
536 dispatchEventForPluginEventSystem(
537 nextDiscreteEvent.domEventName,
538 nextDiscreteEvent.eventSystemFlags,
@@ -538,6 +540,7 @@ function replayUnblockedEvents() {
540 return_targetInst,
541 targetContainer,
542 );
543 + resetReplayingEvent();
544 } else {
545 // We're still blocked. Try again later.
546 nextDiscreteEvent.blockedOn = nextBlockedOn;
packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js
+2 -2
@@ -13,7 +13,7 @@ import type {DispatchQueue} from '../DOMPluginEventSystem';
13 import type {EventSystemFlags} from '../EventSystemFlags';
14
15 import {registerDirectEvent} from '../EventRegistry';
16 -import {IS_REPLAYED} from 'react-dom/src/events/EventSystemFlags';
16 +import {isReplayingEvent} from '../CurrentReplayingEvent';
17 import {SyntheticMouseEvent, SyntheticPointerEvent} from '../SyntheticEvent';
18 import {
19 getClosestInstanceFromNode,
@@ -54,7 +54,7 @@ function extractEvents(
54 const isOutEvent =
55 domEventName === 'mouseout' || domEventName === 'pointerout';
56
57 - if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
57 + if (isOverEvent && !isReplayingEvent(nativeEvent)) {
58 // If this is an over event with a target, we might have already dispatched
59 // the event in the out event of the other target. If this is replayed,
60 // then it's because we couldn't dispatch against this target previously