@samitouri / QOS-React / commits / d6d5f5aabe

Move accumulateEventTargetListeners to its own module/function (#18407)

Dominic Gannaway committed Apr 1, 2020 at 14:19 UTC d6d5f5aabef12386e45acfd13bbd0e8a1043bd4c
3 files changed +159 -134
packages/react-dom/src/events/SimpleEventPlugin.js
+20 -1
@@ -37,6 +37,9 @@ import SyntheticUIEvent from './SyntheticUIEvent';
37 import SyntheticWheelEvent from './SyntheticWheelEvent';
38 import getEventCharCode from './getEventCharCode';
39 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';
43
44 // Only used in DEV for exhaustiveness validation.
45 const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
@@ -197,7 +200,23 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
200 nativeEvent,
201 nativeEventTarget,
202 );
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 + }
220 return event;
221 },
222 };
packages/react-dom/src/events/accumulateEventTargetListeners.js new
+55
@@ -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
+84 -133
@@ -8,7 +8,6 @@
8 */
9
10 import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
11 -import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
11 import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
12
13 import {
@@ -23,162 +22,114 @@ import {
22
23 import getListener from 'legacy-events/getListener';
24 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';
26
27 export default function accumulateTwoPhaseListeners(
28 event: ReactSyntheticEvent,
29 accumulateUseEventListeners?: boolean,
35 - eventSystemFlags?: EventSystemFlags,
36 - targetContainer?: null | EventTarget,
30 ): void {
31 const phasedRegistrationNames = event.dispatchConfig.phasedRegistrationNames;
32 const dispatchListeners = [];
33 const dispatchInstances = [];
34
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;
41
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);
57
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);
73 }
74 }
75 }
76 }
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);
86 }
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);
95 }
96 }
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);
114
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));
126 }
127 }
128 }
179 - node = node.return;
129 }
130 + node = node.return;
131 }
132 +
133 // To prevent allocation to the event unless we actually
134 // have listeners we check the length of one of the arrays.
135 if (dispatchListeners.length > 0) {