Skip to content

Commit d6d5f5a

Browse files
authored
Move accumulateEventTargetListeners to its own module/function (#18407)
1 parent dc3c6c9 commit d6d5f5a

3 files changed

Lines changed: 159 additions & 134 deletions

File tree

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ import SyntheticUIEvent from './SyntheticUIEvent';
3737
import SyntheticWheelEvent from './SyntheticWheelEvent';
3838
import getEventCharCode from './getEventCharCode';
3939
import accumulateTwoPhaseListeners from './accumulateTwoPhaseListeners';
40+
import accumulateEventTargetListeners from './accumulateEventTargetListeners';
41+
import {IS_TARGET_EVENT_ONLY} from 'legacy-events/EventSystemFlags';
42+
import {enableUseEventAPI} from 'shared/ReactFeatureFlags';
4043

4144
// Only used in DEV for exhaustiveness validation.
4245
const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
@@ -197,7 +200,23 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
197200
nativeEvent,
198201
nativeEventTarget,
199202
);
200-
accumulateTwoPhaseListeners(event, true, eventSystemFlags, targetContainer);
203+
204+
// For TargetEvent only accumulation, we do not traverse through
205+
// the React tree looking for managed React DOM elements that have
206+
// events. Instead we only check the EventTarget Store Map to see
207+
// if the container has listeners for the particular phase we're
208+
// interested in. This is because we attach the native event listener
209+
// only in the given phase.
210+
if (
211+
enableUseEventAPI &&
212+
eventSystemFlags !== undefined &&
213+
eventSystemFlags & IS_TARGET_EVENT_ONLY &&
214+
targetContainer != null
215+
) {
216+
accumulateEventTargetListeners(event, targetContainer);
217+
} else {
218+
accumulateTwoPhaseListeners(event, true);
219+
}
201220
return event;
202221
},
203222
};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
10+
import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
11+
import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
12+
13+
import {eventTargetEventListenerStore} from './DOMModernPluginEventSystem';
14+
15+
export default function accumulateEventTargetListeners(
16+
event: ReactSyntheticEvent,
17+
targetContainer: EventTarget,
18+
): void {
19+
const dispatchListeners = [];
20+
const dispatchInstances = [];
21+
const eventTypeMap = eventTargetEventListenerStore.get(targetContainer);
22+
if (eventTypeMap !== undefined) {
23+
const type = ((event.type: any): DOMTopLevelEventType);
24+
const listeners = eventTypeMap.get(type);
25+
if (listeners !== undefined) {
26+
const isCapturePhase = (event: any).eventPhase === 1;
27+
28+
if (isCapturePhase) {
29+
const captureListeners = Array.from(listeners.captured);
30+
31+
for (let i = captureListeners.length - 1; i >= 0; i--) {
32+
const listener = captureListeners[i];
33+
const {callback} = listener;
34+
dispatchListeners.push(callback);
35+
dispatchInstances.push(targetContainer);
36+
}
37+
} else {
38+
const bubbleListeners = Array.from(listeners.bubbled);
39+
40+
for (let i = 0; i < bubbleListeners.length; i++) {
41+
const listener = bubbleListeners[i];
42+
const {callback} = listener;
43+
dispatchListeners.push(callback);
44+
dispatchInstances.push(targetContainer);
45+
}
46+
}
47+
}
48+
}
49+
// To prevent allocation to the event unless we actually
50+
// have listeners we check the length of one of the arrays.
51+
if (dispatchListeners.length > 0) {
52+
event._dispatchListeners = dispatchListeners;
53+
event._dispatchInstances = dispatchInstances;
54+
}
55+
}

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

Lines changed: 84 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
*/
99

1010
import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
11-
import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
1211
import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
1312

1413
import {
@@ -23,162 +22,114 @@ import {
2322

2423
import getListener from 'legacy-events/getListener';
2524
import {getListenersFromTarget} from '../client/ReactDOMComponentTree';
26-
import {IS_TARGET_EVENT_ONLY} from 'legacy-events/EventSystemFlags';
27-
import {
28-
eventTargetEventListenerStore,
29-
reactScopeListenerStore,
30-
} from './DOMModernPluginEventSystem';
25+
import {reactScopeListenerStore} from './DOMModernPluginEventSystem';
3126

3227
export default function accumulateTwoPhaseListeners(
3328
event: ReactSyntheticEvent,
3429
accumulateUseEventListeners?: boolean,
35-
eventSystemFlags?: EventSystemFlags,
36-
targetContainer?: null | EventTarget,
3730
): void {
3831
const phasedRegistrationNames = event.dispatchConfig.phasedRegistrationNames;
3932
const dispatchListeners = [];
4033
const dispatchInstances = [];
4134

42-
// For TargetEvent only accumulation, we do not traverse through
43-
// the React tree looking for managed React DOM elements that have
44-
// events. Instead we only check the EventTarget Store Map to see
45-
// if the container has listeners for the particular phase we're
46-
// interested in. This is because we attach the native event listener
47-
// only in the given phase.
48-
if (
49-
enableUseEventAPI &&
50-
accumulateUseEventListeners &&
51-
eventSystemFlags !== undefined &&
52-
eventSystemFlags & IS_TARGET_EVENT_ONLY &&
53-
targetContainer != null
54-
) {
55-
const eventTypeMap = eventTargetEventListenerStore.get(targetContainer);
56-
if (eventTypeMap !== undefined) {
57-
const type = ((event.type: any): DOMTopLevelEventType);
58-
const listeners = eventTypeMap.get(type);
59-
if (listeners !== undefined) {
60-
const isCapturePhase = (event: any).eventPhase === 1;
61-
62-
if (isCapturePhase) {
63-
const captureListeners = Array.from(listeners.captured);
64-
65-
for (let i = captureListeners.length - 1; i >= 0; i--) {
66-
const listener = captureListeners[i];
67-
const {callback} = listener;
68-
dispatchListeners.push(callback);
69-
dispatchInstances.push(targetContainer);
70-
}
71-
} else {
72-
const bubbleListeners = Array.from(listeners.bubbled);
73-
74-
for (let i = 0; i < bubbleListeners.length; i++) {
75-
const listener = bubbleListeners[i];
76-
const {callback} = listener;
77-
dispatchListeners.push(callback);
78-
dispatchInstances.push(targetContainer);
79-
}
80-
}
81-
}
82-
}
83-
} else {
84-
const {bubbled, captured} = phasedRegistrationNames;
85-
// If we are not handling EventTarget only phase, then we're doing the
86-
// usual two phase accumulation using the React fiber tree to pick up
87-
// all relevant useEvent and on* prop events.
88-
let node = event._targetInst;
89-
let lastHostComponent = null;
35+
const {bubbled, captured} = phasedRegistrationNames;
36+
// If we are not handling EventTarget only phase, then we're doing the
37+
// usual two phase accumulation using the React fiber tree to pick up
38+
// all relevant useEvent and on* prop events.
39+
let node = event._targetInst;
40+
let lastHostComponent = null;
9041

91-
// Accumulate all instances and listeners via the target -> root path.
92-
while (node !== null) {
93-
const {stateNode: instance, tag} = node;
94-
// Handle listeners that are on HostComponents (i.e. <div>)
95-
if (instance !== null && tag === HostComponent) {
96-
lastHostComponent = instance;
97-
// For useEvent listenrs
98-
if (
99-
enableModernEventSystem &&
100-
enableUseEventAPI &&
101-
accumulateUseEventListeners
102-
) {
103-
// useEvent event listeners
104-
const targetType = event.type;
105-
const listeners = getListenersFromTarget(instance);
42+
// Accumulate all instances and listeners via the target -> root path.
43+
while (node !== null) {
44+
const {stateNode: instance, tag} = node;
45+
// Handle listeners that are on HostComponents (i.e. <div>)
46+
if (instance !== null && tag === HostComponent) {
47+
lastHostComponent = instance;
48+
// For useEvent listenrs
49+
if (
50+
enableModernEventSystem &&
51+
enableUseEventAPI &&
52+
accumulateUseEventListeners
53+
) {
54+
// useEvent event listeners
55+
const targetType = event.type;
56+
const listeners = getListenersFromTarget(instance);
10657

107-
if (listeners !== null) {
108-
const listenersArr = Array.from(listeners);
109-
for (let i = 0; i < listenersArr.length; i++) {
110-
const listener = listenersArr[i];
111-
const {
112-
callback,
113-
event: {capture, type},
114-
} = listener;
115-
if (type === targetType) {
116-
if (capture === true) {
117-
dispatchListeners.unshift(callback);
118-
dispatchInstances.unshift(node);
119-
} else {
120-
dispatchListeners.push(callback);
121-
dispatchInstances.push(node);
122-
}
58+
if (listeners !== null) {
59+
const listenersArr = Array.from(listeners);
60+
for (let i = 0; i < listenersArr.length; i++) {
61+
const listener = listenersArr[i];
62+
const {
63+
callback,
64+
event: {capture, type},
65+
} = listener;
66+
if (type === targetType) {
67+
if (capture === true) {
68+
dispatchListeners.unshift(callback);
69+
dispatchInstances.unshift(node);
70+
} else {
71+
dispatchListeners.push(callback);
72+
dispatchInstances.push(node);
12373
}
12474
}
12575
}
12676
}
127-
// Standard React on* listeners, i.e. onClick prop
128-
if (captured !== null) {
129-
const captureListener = getListener(node, captured);
130-
if (captureListener != null) {
131-
// Capture listeners/instances should go at the start, so we
132-
// unshift them to the start of the array.
133-
dispatchListeners.unshift(captureListener);
134-
dispatchInstances.unshift(node);
135-
}
77+
}
78+
// Standard React on* listeners, i.e. onClick prop
79+
if (captured !== null) {
80+
const captureListener = getListener(node, captured);
81+
if (captureListener != null) {
82+
// Capture listeners/instances should go at the start, so we
83+
// unshift them to the start of the array.
84+
dispatchListeners.unshift(captureListener);
85+
dispatchInstances.unshift(node);
13686
}
137-
if (bubbled !== null) {
138-
const bubbleListener = getListener(node, bubbled);
139-
if (bubbleListener != null) {
140-
// Bubble listeners/instances should go at the end, so we
141-
// push them to the end of the array.
142-
dispatchListeners.push(bubbleListener);
143-
dispatchInstances.push(node);
144-
}
87+
}
88+
if (bubbled !== null) {
89+
const bubbleListener = getListener(node, bubbled);
90+
if (bubbleListener != null) {
91+
// Bubble listeners/instances should go at the end, so we
92+
// push them to the end of the array.
93+
dispatchListeners.push(bubbleListener);
94+
dispatchInstances.push(node);
14595
}
14696
}
147-
if (
148-
enableModernEventSystem &&
149-
enableUseEventAPI &&
150-
enableScopeAPI &&
151-
accumulateUseEventListeners &&
152-
tag === ScopeComponent &&
153-
lastHostComponent !== null
154-
) {
155-
const reactScope = instance.methods;
156-
const eventTypeMap = reactScopeListenerStore.get(reactScope);
157-
if (eventTypeMap !== undefined) {
158-
const type = ((event.type: any): DOMTopLevelEventType);
159-
const listeners = eventTypeMap.get(type);
160-
if (listeners !== undefined) {
161-
const captureListeners = Array.from(listeners.captured);
162-
const bubbleListeners = Array.from(listeners.bubbled);
97+
}
98+
if (
99+
enableModernEventSystem &&
100+
enableUseEventAPI &&
101+
enableScopeAPI &&
102+
accumulateUseEventListeners &&
103+
tag === ScopeComponent &&
104+
lastHostComponent !== null
105+
) {
106+
const reactScope = instance.methods;
107+
const eventTypeMap = reactScopeListenerStore.get(reactScope);
108+
if (eventTypeMap !== undefined) {
109+
const type = ((event.type: any): DOMTopLevelEventType);
110+
const listeners = eventTypeMap.get(type);
111+
if (listeners !== undefined) {
112+
const captureListeners = Array.from(listeners.captured);
113+
const bubbleListeners = Array.from(listeners.bubbled);
163114

164-
for (let i = 0; i < captureListeners.length; i++) {
165-
const listener = captureListeners[i];
166-
const {callback} = listener;
167-
dispatchListeners.unshift(callback);
168-
dispatchInstances.unshift(((lastHostComponent: any): Element));
169-
}
170-
for (let i = 0; i < bubbleListeners.length; i++) {
171-
const listener = bubbleListeners[i];
172-
const {callback} = listener;
173-
dispatchListeners.push(callback);
174-
dispatchInstances.push(((lastHostComponent: any): Element));
175-
}
115+
for (let i = 0; i < captureListeners.length; i++) {
116+
const listener = captureListeners[i];
117+
const {callback} = listener;
118+
dispatchListeners.unshift(callback);
119+
dispatchInstances.unshift(((lastHostComponent: any): Element));
120+
}
121+
for (let i = 0; i < bubbleListeners.length; i++) {
122+
const listener = bubbleListeners[i];
123+
const {callback} = listener;
124+
dispatchListeners.push(callback);
125+
dispatchInstances.push(((lastHostComponent: any): Element));
176126
}
177127
}
178128
}
179-
node = node.return;
180129
}
130+
node = node.return;
181131
}
132+
182133
// To prevent allocation to the event unless we actually
183134
// have listeners we check the length of one of the arrays.
184135
if (dispatchListeners.length > 0) {

0 commit comments

Comments
 (0)