Enable eager listeners statically (#19983)
Dan Abramov committed
Oct 8, 2020 at 19:32 UTC
993ca533b42756811731f6b7791ae06a35ee6b4d
21 files changed
+55
-402
packages/react-dom/src/__tests__/ReactDOMFiber-test.js
-1
@@ -1040,7 +1040,6 @@ describe('ReactDOMFiber', () => {
1040
expect(ops).toEqual([]);
1041
});
1042
1043
- // @gate enableEagerRootListeners
1043
it('listens to events that do not exist in the Portal subtree', () => {
1044
const onClick = jest.fn();
1045
packages/react-dom/src/client/ReactDOMComponent.js
+5
-83
@@ -61,12 +61,7 @@ import {
61
shouldRemoveAttribute,
62
} from '../shared/DOMProperty';
63
import assertValidProps from '../shared/assertValidProps';
64
-import {
65
- DOCUMENT_NODE,
66
- ELEMENT_NODE,
67
- COMMENT_NODE,
68
- DOCUMENT_FRAGMENT_NODE,
69
-} from '../shared/HTMLNodeType';
64
+import {DOCUMENT_NODE} from '../shared/HTMLNodeType';
65
import isCustomComponent from '../shared/isCustomComponent';
66
import possibleStandardNames from '../shared/possibleStandardNames';
67
import {validateProperties as validateARIAProperties} from '../shared/ReactDOMInvalidARIAHook';
@@ -74,12 +69,8 @@ import {validateProperties as validateInputProperties} from '../shared/ReactDOMN
69
import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook';
70
import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
71
72
+import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags';
73
import {
78
- enableTrustedTypesIntegration,
79
- enableEagerRootListeners,
80
-} from 'shared/ReactFeatureFlags';
81
-import {
82
- listenToReactEvent,
74
mediaEventTypes,
75
listenToNonDelegatedEvent,
76
} from '../events/DOMPluginEventSystem';
@@ -253,39 +244,6 @@ if (__DEV__) {
244
};
245
}
246
256
-export function ensureListeningTo(
257
- rootContainerInstance: Element | Node,
258
- reactPropEvent: string,
259
- targetElement: Element | null,
260
-): void {
261
- if (!enableEagerRootListeners) {
262
- // If we have a comment node, then use the parent node,
263
- // which should be an element.
264
- const rootContainerElement =
265
- rootContainerInstance.nodeType === COMMENT_NODE
266
- ? rootContainerInstance.parentNode
267
- : rootContainerInstance;
268
- if (__DEV__) {
269
- if (
270
- rootContainerElement == null ||
271
- (rootContainerElement.nodeType !== ELEMENT_NODE &&
272
- // This is to support rendering into a ShadowRoot:
273
- rootContainerElement.nodeType !== DOCUMENT_FRAGMENT_NODE)
274
- ) {
275
- console.error(
276
- 'ensureListeningTo(): received a container that was not an element node. ' +
277
- 'This is likely a bug in React. Please file an issue.',
278
- );
279
- }
280
- }
281
- listenToReactEvent(
282
- reactPropEvent,
283
- ((rootContainerElement: any): Element),
284
- targetElement,
285
- );
286
- }
287
-}
288
-
247
function getOwnerDocumentFromRootContainer(
248
rootContainerElement: Element | Document,
249
): Document {
@@ -364,9 +322,7 @@ function setInitialDOMProperties(
322
if (__DEV__ && typeof nextProp !== 'function') {
323
warnForInvalidEventListener(propKey, nextProp);
324
}
367
- if (!enableEagerRootListeners) {
368
- ensureListeningTo(rootContainerElement, propKey, domElement);
369
- } else if (propKey === 'onScroll') {
325
+ if (propKey === 'onScroll') {
326
listenToNonDelegatedEvent('scroll', domElement);
327
}
328
}
@@ -577,11 +533,6 @@ export function setInitialProperties(
533
// We listen to this event in case to ensure emulated bubble
534
// listeners still fire for the invalid event.
535
listenToNonDelegatedEvent('invalid', domElement);
580
- if (!enableEagerRootListeners) {
581
- // For controlled components we always need to ensure we're listening
582
- // to onChange. Even if there is no listener.
583
- ensureListeningTo(rootContainerElement, 'onChange', domElement);
584
- }
536
break;
537
case 'option':
538
ReactDOMOptionValidateProps(domElement, rawProps);
@@ -593,11 +544,6 @@ export function setInitialProperties(
544
// We listen to this event in case to ensure emulated bubble
545
// listeners still fire for the invalid event.
546
listenToNonDelegatedEvent('invalid', domElement);
596
- if (!enableEagerRootListeners) {
597
- // For controlled components we always need to ensure we're listening
598
- // to onChange. Even if there is no listener.
599
- ensureListeningTo(rootContainerElement, 'onChange', domElement);
600
- }
547
break;
548
case 'textarea':
549
ReactDOMTextareaInitWrapperState(domElement, rawProps);
@@ -605,11 +551,6 @@ export function setInitialProperties(
551
// We listen to this event in case to ensure emulated bubble
552
// listeners still fire for the invalid event.
553
listenToNonDelegatedEvent('invalid', domElement);
608
- if (!enableEagerRootListeners) {
609
- // For controlled components we always need to ensure we're listening
610
- // to onChange. Even if there is no listener.
611
- ensureListeningTo(rootContainerElement, 'onChange', domElement);
612
- }
554
break;
555
default:
556
props = rawProps;
@@ -827,9 +768,7 @@ export function diffProperties(
768
if (__DEV__ && typeof nextProp !== 'function') {
769
warnForInvalidEventListener(propKey, nextProp);
770
}
830
- if (!enableEagerRootListeners) {
831
- ensureListeningTo(rootContainerElement, propKey, domElement);
832
- } else if (propKey === 'onScroll') {
771
+ if (propKey === 'onScroll') {
772
listenToNonDelegatedEvent('scroll', domElement);
773
}
774
}
@@ -983,11 +922,6 @@ export function diffHydratedProperties(
922
// We listen to this event in case to ensure emulated bubble
923
// listeners still fire for the invalid event.
924
listenToNonDelegatedEvent('invalid', domElement);
986
- if (!enableEagerRootListeners) {
987
- // For controlled components we always need to ensure we're listening
988
- // to onChange. Even if there is no listener.
989
- ensureListeningTo(rootContainerElement, 'onChange', domElement);
990
- }
925
break;
926
case 'option':
927
ReactDOMOptionValidateProps(domElement, rawProps);
@@ -997,22 +931,12 @@ export function diffHydratedProperties(
931
// We listen to this event in case to ensure emulated bubble
932
// listeners still fire for the invalid event.
933
listenToNonDelegatedEvent('invalid', domElement);
1000
- if (!enableEagerRootListeners) {
1001
- // For controlled components we always need to ensure we're listening
1002
- // to onChange. Even if there is no listener.
1003
- ensureListeningTo(rootContainerElement, 'onChange', domElement);
1004
- }
934
break;
935
case 'textarea':
936
ReactDOMTextareaInitWrapperState(domElement, rawProps);
937
// We listen to this event in case to ensure emulated bubble
938
// listeners still fire for the invalid event.
939
listenToNonDelegatedEvent('invalid', domElement);
1011
- if (!enableEagerRootListeners) {
1012
- // For controlled components we always need to ensure we're listening
1013
- // to onChange. Even if there is no listener.
1014
- ensureListeningTo(rootContainerElement, 'onChange', domElement);
1015
- }
940
break;
941
}
942
@@ -1079,9 +1003,7 @@ export function diffHydratedProperties(
1003
if (__DEV__ && typeof nextProp !== 'function') {
1004
warnForInvalidEventListener(propKey, nextProp);
1005
}
1082
- if (!enableEagerRootListeners) {
1083
- ensureListeningTo(rootContainerElement, propKey, domElement);
1084
- } else if (propKey === 'onScroll') {
1006
+ if (propKey === 'onScroll') {
1007
listenToNonDelegatedEvent('scroll', domElement);
1008
}
1009
}
packages/react-dom/src/client/ReactDOMEventHandle.js
+3
-84
@@ -16,23 +16,19 @@ import type {
16
17
import {allNativeEvents} from '../events/EventRegistry';
18
import {
19
- getClosestInstanceFromNode,
19
getEventHandlerListeners,
20
setEventHandlerListeners,
22
- getFiberFromScopeInstance,
21
doesTargetHaveEventHandle,
22
addEventHandleToTarget,
23
} from './ReactDOMComponentTree';
26
-import {ELEMENT_NODE, COMMENT_NODE} from '../shared/HTMLNodeType';
24
+import {ELEMENT_NODE} from '../shared/HTMLNodeType';
25
import {listenToNativeEvent} from '../events/DOMPluginEventSystem';
26
29
-import {HostRoot, HostPortal} from 'react-reconciler/src/ReactWorkTags';
27
import {IS_EVENT_HANDLE_NON_MANAGED_NODE} from '../events/EventSystemFlags';
28
29
import {
30
enableScopeAPI,
31
enableCreateEventHandleAPI,
35
- enableEagerRootListeners,
32
} from 'shared/ReactFeatureFlags';
33
import invariant from 'shared/invariant';
34
@@ -40,19 +36,6 @@ type EventHandleOptions = {|
36
capture?: boolean,
37
|};
38
43
-function getNearestRootOrPortalContainer(node: Fiber): null | Element {
44
- while (node !== null) {
45
- const tag = node.tag;
46
- // Once we encounter a host container or root container
47
- // we can return their DOM instance.
48
- if (tag === HostRoot || tag === HostPortal) {
49
- return node.stateNode.containerInfo;
50
- }
51
- node = node.return;
52
- }
53
- return null;
54
-}
55
-
39
function isValidEventTarget(target: EventTarget | ReactScopeInstance): boolean {
40
return typeof (target: Object).addEventListener === 'function';
41
}
@@ -73,79 +56,15 @@ function createEventHandleListener(
56
};
57
}
58
76
-function registerEventOnNearestTargetContainer(
77
- targetFiber: Fiber,
78
- domEventName: DOMEventName,
79
- isCapturePhaseListener: boolean,
80
- targetElement: Element | null,
81
-): void {
82
- if (!enableEagerRootListeners) {
83
- // If it is, find the nearest root or portal and make it
84
- // our event handle target container.
85
- let targetContainer = getNearestRootOrPortalContainer(targetFiber);
86
- if (targetContainer === null) {
87
- if (__DEV__) {
88
- console.error(
89
- 'ReactDOM.createEventHandle: setListener called on an target ' +
90
- 'that did not have a corresponding root. This is likely a bug in React.',
91
- );
92
- }
93
- return;
94
- }
95
- if (targetContainer.nodeType === COMMENT_NODE) {
96
- targetContainer = ((targetContainer.parentNode: any): Element);
97
- }
98
- listenToNativeEvent(
99
- domEventName,
100
- isCapturePhaseListener,
101
- targetContainer,
102
- targetElement,
103
- );
104
- }
105
-}
106
-
59
function registerReactDOMEvent(
60
target: EventTarget | ReactScopeInstance,
61
domEventName: DOMEventName,
62
isCapturePhaseListener: boolean,
63
): void {
112
- // Check if the target is a DOM element.
64
if ((target: any).nodeType === ELEMENT_NODE) {
114
- if (!enableEagerRootListeners) {
115
- const targetElement = ((target: any): Element);
116
- // Check if the DOM element is managed by React.
117
- const targetFiber = getClosestInstanceFromNode(targetElement);
118
- if (targetFiber === null) {
119
- if (__DEV__) {
120
- console.error(
121
- 'ReactDOM.createEventHandle: setListener called on an element ' +
122
- 'target that is not managed by React. Ensure React rendered the DOM element.',
123
- );
124
- }
125
- return;
126
- }
127
- registerEventOnNearestTargetContainer(
128
- targetFiber,
129
- domEventName,
130
- isCapturePhaseListener,
131
- targetElement,
132
- );
133
- }
65
+ // Do nothing. We already attached all root listeners.
66
} else if (enableScopeAPI && isReactScope(target)) {
135
- if (!enableEagerRootListeners) {
136
- const scopeTarget = ((target: any): ReactScopeInstance);
137
- const targetFiber = getFiberFromScopeInstance(scopeTarget);
138
- if (targetFiber === null) {
139
- // Scope is unmounted, do not proceed.
140
- return;
141
- }
142
- registerEventOnNearestTargetContainer(
143
- targetFiber,
144
- domEventName,
145
- isCapturePhaseListener,
146
- null,
147
- );
148
- }
67
+ // Do nothing. We already attached all root listeners.
68
} else if (isValidEventTarget(target)) {
69
const eventTarget = ((target: any): EventTarget);
70
// These are valid event targets, but they are also
packages/react-dom/src/client/ReactDOMHostConfig.js
+2
-10
@@ -67,13 +67,9 @@ import {
67
enableFundamentalAPI,
68
enableCreateEventHandleAPI,
69
enableScopeAPI,
70
- enableEagerRootListeners,
70
} from 'shared/ReactFeatureFlags';
71
import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
73
-import {
74
- listenToReactEvent,
75
- listenToAllSupportedEvents,
76
-} from '../events/DOMPluginEventSystem';
72
+import {listenToAllSupportedEvents} from '../events/DOMPluginEventSystem';
73
74
export type Type = string;
75
export type Props = {
@@ -1073,11 +1069,7 @@ export function makeOpaqueHydratingObject(
1069
}
1070
1071
export function preparePortalMount(portalInstance: Instance): void {
1076
- if (enableEagerRootListeners) {
1077
- listenToAllSupportedEvents(portalInstance);
1078
- } else {
1079
- listenToReactEvent('onMouseEnter', portalInstance, null);
1080
- }
1072
+ listenToAllSupportedEvents(portalInstance);
1073
}
1074
1075
export function prepareScopeUpdate(
packages/react-dom/src/client/ReactDOMRoot.js
+4
-27
@@ -36,14 +36,12 @@ import {
36
unmarkContainerAsRoot,
37
} from './ReactDOMComponentTree';
38
import {listenToAllSupportedEvents} from '../events/DOMPluginEventSystem';
39
-import {eagerlyTrapReplayableEvents} from '../events/ReactDOMEventReplaying';
39
import {
40
ELEMENT_NODE,
41
COMMENT_NODE,
42
DOCUMENT_NODE,
43
DOCUMENT_FRAGMENT_NODE,
44
} from '../shared/HTMLNodeType';
46
-import {ensureListeningTo} from './ReactDOMComponent';
45
46
import {
47
createContainer,
@@ -52,7 +50,6 @@ import {
50
registerMutableSourceForHydration,
51
} from 'react-reconciler/src/ReactFiberReconciler';
52
import invariant from 'shared/invariant';
55
-import {enableEagerRootListeners} from 'shared/ReactFeatureFlags';
53
import {
54
BlockingRoot,
55
ConcurrentRoot,
@@ -133,30 +130,10 @@ function createRootImpl(
130
null;
131
const root = createContainer(container, tag, hydrate, hydrationCallbacks);
132
markContainerAsRoot(root.current, container);
136
- const containerNodeType = container.nodeType;
137
-
138
- if (enableEagerRootListeners) {
139
- const rootContainerElement =
140
- container.nodeType === COMMENT_NODE ? container.parentNode : container;
141
- listenToAllSupportedEvents(rootContainerElement);
142
- } else {
143
- if (hydrate && tag !== LegacyRoot) {
144
- const doc =
145
- containerNodeType === DOCUMENT_NODE
146
- ? container
147
- : container.ownerDocument;
148
- // We need to cast this because Flow doesn't work
149
- // with the hoisted containerNodeType. If we inline
150
- // it, then Flow doesn't complain. We intentionally
151
- // hoist it to reduce code-size.
152
- eagerlyTrapReplayableEvents(container, ((doc: any): Document));
153
- } else if (
154
- containerNodeType !== DOCUMENT_FRAGMENT_NODE &&
155
- containerNodeType !== DOCUMENT_NODE
156
- ) {
157
- ensureListeningTo(container, 'onMouseEnter', null);
158
- }
159
- }
133
+
134
+ const rootContainerElement =
135
+ container.nodeType === COMMENT_NODE ? container.parentNode : container;
136
+ listenToAllSupportedEvents(rootContainerElement);
137
138
if (mutableSources) {
139
for (let i = 0; i < mutableSources.length; i++) {
packages/react-dom/src/events/DOMPluginEventSystem.js
+20
-77
@@ -21,7 +21,7 @@ import type {
21
} from './ReactSyntheticEventType';
22
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
23
24
-import {registrationNameDependencies, allNativeEvents} from './EventRegistry';
24
+import {allNativeEvents} from './EventRegistry';
25
import {
26
IS_CAPTURE_PHASE,
27
IS_EVENT_HANDLE_NON_MANAGED_NODE,
@@ -51,7 +51,6 @@ import {
51
enableLegacyFBSupport,
52
enableCreateEventHandleAPI,
53
enableScopeAPI,
54
- enableEagerRootListeners,
54
} from 'shared/ReactFeatureFlags';
55
import {
56
invokeGuardedCallbackAndCatchFirstError,
@@ -320,32 +319,30 @@ const listeningMarker =
319
.slice(2);
320
321
export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
323
- if (enableEagerRootListeners) {
324
- if ((rootContainerElement: any)[listeningMarker]) {
325
- // Performance optimization: don't iterate through events
326
- // for the same portal container or root node more than once.
327
- // TODO: once we remove the flag, we may be able to also
328
- // remove some of the bookkeeping maps used for laziness.
329
- return;
330
- }
331
- (rootContainerElement: any)[listeningMarker] = true;
332
- allNativeEvents.forEach(domEventName => {
333
- if (!nonDelegatedEvents.has(domEventName)) {
334
- listenToNativeEvent(
335
- domEventName,
336
- false,
337
- ((rootContainerElement: any): Element),
338
- null,
339
- );
340
- }
322
+ if ((rootContainerElement: any)[listeningMarker]) {
323
+ // Performance optimization: don't iterate through events
324
+ // for the same portal container or root node more than once.
325
+ // TODO: once we remove the flag, we may be able to also
326
+ // remove some of the bookkeeping maps used for laziness.
327
+ return;
328
+ }
329
+ (rootContainerElement: any)[listeningMarker] = true;
330
+ allNativeEvents.forEach(domEventName => {
331
+ if (!nonDelegatedEvents.has(domEventName)) {
332
listenToNativeEvent(
333
domEventName,
343
- true,
334
+ false,
335
((rootContainerElement: any): Element),
336
null,
337
);
347
- });
348
- }
338
+ }
339
+ listenToNativeEvent(
340
+ domEventName,
341
+ true,
342
+ ((rootContainerElement: any): Element),
343
+ null,
344
+ );
345
+ });
346
}
347
348
export function listenToNativeEvent(
@@ -411,60 +408,6 @@ export function listenToNativeEvent(
408
}
409
}
410
414
-export function listenToReactEvent(
415
- reactEvent: string,
416
- rootContainerElement: Element,
417
- targetElement: Element | null,
418
-): void {
419
- if (!enableEagerRootListeners) {
420
- const dependencies = registrationNameDependencies[reactEvent];
421
- const dependenciesLength = dependencies.length;
422
- // If the dependencies length is 1, that means we're not using a polyfill
423
- // plugin like ChangeEventPlugin, BeforeInputPlugin, EnterLeavePlugin
424
- // and SelectEventPlugin. We always use the native bubble event phase for
425
- // these plugins and emulate two phase event dispatching. SimpleEventPlugin
426
- // always only has a single dependency and SimpleEventPlugin events also
427
- // use either the native capture event phase or bubble event phase, there
428
- // is no emulation (except for focus/blur, but that will be removed soon).
429
- const isPolyfillEventPlugin = dependenciesLength !== 1;
430
-
431
- if (isPolyfillEventPlugin) {
432
- const listenerSet = getEventListenerSet(rootContainerElement);
433
- // When eager listeners are off, this Set has a dual purpose: it both
434
- // captures which native listeners we registered (e.g. "click__bubble")
435
- // and *React* lazy listeners (e.g. "onClick") so we don't do extra checks.
436
- // This second usage does not exist in the eager mode.
437
- if (!listenerSet.has(reactEvent)) {
438
- listenerSet.add(reactEvent);
439
- for (let i = 0; i < dependenciesLength; i++) {
440
- listenToNativeEvent(
441
- dependencies[i],
442
- false,
443
- rootContainerElement,
444
- targetElement,
445
- );
446
- }
447
- }
448
- } else {
449
- const isCapturePhaseListener =
450
- reactEvent.substr(-7) === 'Capture' &&
451
- // Edge case: onGotPointerCapture and onLostPointerCapture
452
- // end with "Capture" but that's part of their event names.
453
- // The Capture versions would end with CaptureCapture.
454
- // So we have to check against that.
455
- // This check works because none of the events we support
456
- // end with "Pointer".
457
- reactEvent.substr(-14, 7) !== 'Pointer';
458
- listenToNativeEvent(
459
- dependencies[0],
460
- isCapturePhaseListener,
461
- rootContainerElement,
462
- targetElement,
463
- );
464
- }
465
- }
466
-}
467
-
411
function addTrappedEventListener(
412
targetContainer: EventTarget,
413
domEventName: DOMEventName,
packages/react-dom/src/events/ReactDOMEventListener.js
+8
-11
@@ -40,7 +40,6 @@ import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
40
41
import {
42
enableLegacyFBSupport,
43
- enableEagerRootListeners,
43
decoupleUpdatePriorityFromScheduler,
44
} from 'shared/ReactFeatureFlags';
45
import {
@@ -188,16 +187,14 @@ export function dispatchEvent(
187
if (!_enabled) {
188
return;
189
}
191
- let allowReplay = true;
192
- if (enableEagerRootListeners) {
193
- // TODO: replaying capture phase events is currently broken
194
- // because we used to do it during top-level native bubble handlers
195
- // but now we use different bubble and capture handlers.
196
- // In eager mode, we attach capture listeners early, so we need
197
- // to filter them out until we fix the logic to handle them correctly.
198
- // This could've been outside the flag but I put it inside to reduce risk.
199
- allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0;
200
- }
190
+
191
+ // TODO: replaying capture phase events is currently broken
192
+ // because we used to do it during top-level native bubble handlers
193
+ // but now we use different bubble and capture handlers.
194
+ // In eager mode, we attach capture listeners early, so we need
195
+ // to filter them out until we fix the logic to handle them correctly.
196
+ const allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0;
197
+
198
if (
199
allowReplay &&
200
hasQueuedDiscreteEvents() &&
packages/react-dom/src/events/ReactDOMEventReplaying.js
+1
-45
@@ -14,10 +14,7 @@ import type {EventSystemFlags} from './EventSystemFlags';
14
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
15
import type {LanePriority} from 'react-reconciler/src/ReactFiberLane';
16
17
-import {
18
- enableSelectiveHydration,
19
- enableEagerRootListeners,
20
-} from 'shared/ReactFeatureFlags';
17
+import {enableSelectiveHydration} from 'shared/ReactFeatureFlags';
18
import {
19
unstable_runWithPriority as runWithPriority,
20
unstable_scheduleCallback as scheduleCallback,
@@ -85,7 +82,6 @@ type PointerEvent = Event & {
82
};
83
84
import {IS_REPLAYED} from './EventSystemFlags';
88
-import {listenToNativeEvent} from './DOMPluginEventSystem';
85
86
type QueuedReplayableEvent = {|
87
blockedOn: null | Container | SuspenseInstance,
@@ -159,50 +155,10 @@ const discreteReplayableEvents: Array<DOMEventName> = [
155
'submit',
156
];
157
162
-const continuousReplayableEvents: Array<DOMEventName> = [
163
- 'dragenter',
164
- 'dragleave',
165
- 'focusin',
166
- 'focusout',
167
- 'mouseover',
168
- 'mouseout',
169
- 'pointerover',
170
- 'pointerout',
171
- 'gotpointercapture',
172
- 'lostpointercapture',
173
-];
174
-
158
export function isReplayableDiscreteEvent(eventType: DOMEventName): boolean {
159
return discreteReplayableEvents.indexOf(eventType) > -1;
160
}
161
179
-function trapReplayableEventForContainer(
180
- domEventName: DOMEventName,
181
- container: Container,
182
-) {
183
- // When the flag is on, we do this in a unified codepath elsewhere.
184
- if (!enableEagerRootListeners) {
185
- listenToNativeEvent(domEventName, false, ((container: any): Element), null);
186
- }
187
-}
188
-
189
-export function eagerlyTrapReplayableEvents(
190
- container: Container,
191
- document: Document,
192
-) {
193
- // When the flag is on, we do this in a unified codepath elsewhere.
194
- if (!enableEagerRootListeners) {
195
- // Discrete
196
- discreteReplayableEvents.forEach(domEventName => {
197
- trapReplayableEventForContainer(domEventName, container);
198
- });
199
- // Continuous
200
- continuousReplayableEvents.forEach(domEventName => {
201
- trapReplayableEventForContainer(domEventName, container);
202
- });
203
- }
204
-}
205
-
162
function createQueuedReplayableEvent(
163
blockedOn: null | Container | SuspenseInstance,
164
domEventName: DOMEventName,
packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js
+1
-1
@@ -2643,7 +2643,7 @@ describe('DOMPluginEventSystem', () => {
2643
expect(log[5]).toEqual(['bubble', buttonElement]);
2644
});
2645
2646
- // @gate experimental && enableEagerRootListeners
2646
+ // @gate experimental
2647
it('propagates known createEventHandle events through portals without inner listeners', () => {
2648
const buttonRef = React.createRef();
2649
const divRef = React.createRef();
packages/react-dom/src/events/plugins/SelectEventPlugin.js
+1
-22
@@ -16,14 +16,10 @@ import {canUseDOM} from 'shared/ExecutionEnvironment';
16
import {SyntheticEvent} from '../../events/SyntheticEvent';
17
import isTextInputElement from '../isTextInputElement';
18
import shallowEqual from 'shared/shallowEqual';
19
-import {enableEagerRootListeners} from 'shared/ReactFeatureFlags';
19
20
import {registerTwoPhaseEvent} from '../EventRegistry';
21
import getActiveElement from '../../client/getActiveElement';
23
-import {
24
- getNodeFromInstance,
25
- getEventListenerSet,
26
-} from '../../client/ReactDOMComponentTree';
22
+import {getNodeFromInstance} from '../../client/ReactDOMComponentTree';
23
import {hasSelectionCapabilities} from '../../client/ReactInputSelection';
24
import {DOCUMENT_NODE} from '../../shared/HTMLNodeType';
25
import {accumulateTwoPhaseListeners} from '../DOMPluginEventSystem';
@@ -154,23 +150,6 @@ function extractEvents(
150
eventSystemFlags: EventSystemFlags,
151
targetContainer: EventTarget,
152
) {
157
- if (!enableEagerRootListeners) {
158
- const eventListenerSet = getEventListenerSet(targetContainer);
159
- // Track whether all listeners exists for this plugin. If none exist, we do
160
- // not extract events. See #3639.
161
- if (
162
- // If we are handling selectionchange, then we don't need to
163
- // check for the other dependencies, as selectionchange is only
164
- // event attached from the onChange plugin and we don't expose an
165
- // onSelectionChange event from React.
166
- domEventName !== 'selectionchange' &&
167
- !eventListenerSet.has('onSelect') &&
168
- !eventListenerSet.has('onSelectCapture')
169
- ) {
170
- return;
171
- }
172
- }
173
-
153
const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
154
155
switch (domEventName) {
packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js
+10
-30
@@ -516,36 +516,16 @@ describe('SimpleEventPlugin', function() {
516
return nativeAddEventListener.apply(this, arguments);
517
};
518
519
- ReactDOM.render(
520
- <div
521
- // Affected by the intervention:
522
- // https://github.com/facebook/react/issues/19651
523
- onTouchStart={() => {}}
524
- onTouchMove={() => {}}
525
- onWheel={() => {}}
526
- // A few events that should be unaffected:
527
- onClick={() => {}}
528
- onScroll={() => {}}
529
- onTouchEnd={() => {}}
530
- onChange={() => {}}
531
- onPointerDown={() => {}}
532
- onPointerMove={() => {}}
533
- />,
534
- container,
535
- );
536
-
537
- if (gate(flags => flags.enableEagerRootListeners)) {
538
- expect(passiveEvents).toEqual([
539
- 'touchstart',
540
- 'touchstart',
541
- 'touchmove',
542
- 'touchmove',
543
- 'wheel',
544
- 'wheel',
545
- ]);
546
- } else {
547
- expect(passiveEvents).toEqual(['touchstart', 'touchmove', 'wheel']);
548
- }
519
+ ReactDOM.render(<div />, container);
520
+
521
+ expect(passiveEvents).toEqual([
522
+ 'touchstart',
523
+ 'touchstart',
524
+ 'touchmove',
525
+ 'touchmove',
526
+ 'wheel',
527
+ 'wheel',
528
+ ]);
529
});
530
});
531
});
packages/shared/ReactFeatureFlags.js
-2
@@ -133,6 +133,4 @@ export const decoupleUpdatePriorityFromScheduler = false;
133
134
export const enableDiscreteEventFlushingChange = false;
135
136
-export const enableEagerRootListeners = true;
137
-
136
export const enableDoubleInvokingEffects = false;
packages/shared/forks/ReactFeatureFlags.native-fb.js
-1
@@ -49,7 +49,6 @@ export const enableNewReconciler = false;
49
export const deferRenderPhaseUpdateToNextBatch = true;
50
export const decoupleUpdatePriorityFromScheduler = false;
51
export const enableDiscreteEventFlushingChange = false;
52
-export const enableEagerRootListeners = true;
52
53
export const enableDoubleInvokingEffects = false;
54
packages/shared/forks/ReactFeatureFlags.native-oss.js
-1
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
48
export const deferRenderPhaseUpdateToNextBatch = true;
49
export const decoupleUpdatePriorityFromScheduler = false;
50
export const enableDiscreteEventFlushingChange = false;
51
-export const enableEagerRootListeners = true;
51
52
export const enableDoubleInvokingEffects = false;
53
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-1
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
48
export const deferRenderPhaseUpdateToNextBatch = true;
49
export const decoupleUpdatePriorityFromScheduler = false;
50
export const enableDiscreteEventFlushingChange = false;
51
-export const enableEagerRootListeners = true;
51
52
export const enableDoubleInvokingEffects = false;
53
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
-1
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
48
export const deferRenderPhaseUpdateToNextBatch = true;
49
export const decoupleUpdatePriorityFromScheduler = false;
50
export const enableDiscreteEventFlushingChange = false;
51
-export const enableEagerRootListeners = true;
51
52
export const enableDoubleInvokingEffects = false;
53
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-1
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
48
export const deferRenderPhaseUpdateToNextBatch = true;
49
export const decoupleUpdatePriorityFromScheduler = false;
50
export const enableDiscreteEventFlushingChange = false;
51
-export const enableEagerRootListeners = true;
51
52
export const enableDoubleInvokingEffects = false;
53
packages/shared/forks/ReactFeatureFlags.testing.js
-1
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
48
export const deferRenderPhaseUpdateToNextBatch = true;
49
export const decoupleUpdatePriorityFromScheduler = false;
50
export const enableDiscreteEventFlushingChange = false;
51
-export const enableEagerRootListeners = true;
51
52
export const enableDoubleInvokingEffects = false;
53
packages/shared/forks/ReactFeatureFlags.testing.www.js
-1
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
48
export const deferRenderPhaseUpdateToNextBatch = true;
49
export const decoupleUpdatePriorityFromScheduler = false;
50
export const enableDiscreteEventFlushingChange = true;
51
-export const enableEagerRootListeners = true;
51
52
export const enableDoubleInvokingEffects = false;
53
packages/shared/forks/ReactFeatureFlags.www-dynamic.js
-1
@@ -19,7 +19,6 @@ export const enableFilterEmptyStringAttributesDOM = __VARIANT__;
19
export const enableLegacyFBSupport = __VARIANT__;
20
export const decoupleUpdatePriorityFromScheduler = __VARIANT__;
21
export const skipUnmountedBoundaries = __VARIANT__;
22
-export const enableEagerRootListeners = !__VARIANT__;
22
23
// Enable this flag to help with concurrent mode debugging.
24
// It logs information to the console about React scheduling, rendering, and commit phases.
packages/shared/forks/ReactFeatureFlags.www.js
-1
@@ -27,7 +27,6 @@ export const {
27
decoupleUpdatePriorityFromScheduler,
28
enableDebugTracing,
29
skipUnmountedBoundaries,
30
- enableEagerRootListeners,
30
enableDoubleInvokingEffects,
31
} = dynamicFeatureFlags;
32