@samitouri / QOS-React-2 / commits / 30a998debf

ModernEventSystem: refactor accumulateTwoPhaseListeners (#18274)

Dominic Gannaway committed Mar 11, 2020 at 18:55 UTC 30a998debf79f8c8efb3fa9b6ff5458fb319d7a1
7 files changed +60 -10
packages/legacy-events/ReactSyntheticEventType.js
+3
@@ -31,4 +31,7 @@ export type ReactSyntheticEvent = {|
31 nativeEventTarget: EventTarget,
32 ) => ReactSyntheticEvent,
33 isPersistent: () => boolean,
34 + _dispatchInstances: null | Array<Fiber>,
35 + _dispatchListeners: null | Array<Function>,
36 + _targetInst: null | Fiber,
37 |};
packages/legacy-events/SyntheticEvent.js
+2
@@ -76,6 +76,8 @@ function SyntheticEvent(
76 this.dispatchConfig = dispatchConfig;
77 this._targetInst = targetInst;
78 this.nativeEvent = nativeEvent;
79 + this._dispatchListeners = null;
80 + this._dispatchInstances = null;
81
82 const Interface = this.constructor.Interface;
83 for (const propName in Interface) {
packages/react-dom/src/events/BeforeInputEventPlugin.js
+3 -3
@@ -7,7 +7,6 @@
7
8 import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
9
10 -import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
10 import {canUseDOM} from 'shared/ExecutionEnvironment';
11
12 import {
@@ -29,6 +28,7 @@ import {
28 } from './FallbackCompositionState';
29 import SyntheticCompositionEvent from './SyntheticCompositionEvent';
30 import SyntheticInputEvent from './SyntheticInputEvent';
31 +import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
32
33 const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
34 const START_KEYCODE = 229;
@@ -276,7 +276,7 @@ function extractCompositionEvent(
276 }
277 }
278
279 - accumulateTwoPhaseDispatchesSingle(event);
279 + accumulateTwoPhaseListeners(event);
280 return event;
281 }
282
@@ -437,7 +437,7 @@ function extractBeforeInputEvent(
437 );
438
439 event.data = chars;
440 - accumulateTwoPhaseDispatchesSingle(event);
440 + accumulateTwoPhaseListeners(event);
441 return event;
442 }
443
packages/react-dom/src/events/ChangeEventPlugin.js
+3 -2
@@ -6,7 +6,6 @@
6 */
7
8 import {runEventsInBatch} from 'legacy-events/EventBatching';
9 -import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
9 import {enqueueStateRestore} from 'legacy-events/ReactControlledComponent';
10 import {batchedUpdates} from 'legacy-events/ReactGenericBatching';
11 import SyntheticEvent from 'legacy-events/SyntheticEvent';
@@ -28,6 +27,8 @@ import isEventSupported from './isEventSupported';
27 import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
28 import {updateValueIfChanged} from '../client/inputValueTracking';
29 import {setDefaultValue} from '../client/ReactDOMInput';
30 +import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
31 +
32 import {disableInputAttributeSyncing} from 'shared/ReactFeatureFlags';
33
34 const eventTypes = {
@@ -59,7 +60,7 @@ function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
60 event.type = 'change';
61 // Flag this event loop as needing state restore.
62 enqueueStateRestore(target);
62 - accumulateTwoPhaseDispatchesSingle(event);
63 + accumulateTwoPhaseListeners(event);
64 return event;
65 }
66 /**
packages/react-dom/src/events/DOMModernPluginEventSystem.js
+45 -1
@@ -19,8 +19,9 @@ import {registrationNameDependencies} from 'legacy-events/EventPluginRegistry';
19 import {batchedEventUpdates} from 'legacy-events/ReactGenericBatching';
20 import {executeDispatchesInOrder} from 'legacy-events/EventPluginUtils';
21 import {plugins} from 'legacy-events/EventPluginRegistry';
22 +import getListener from 'legacy-events/getListener';
23
23 -import {HostRoot, HostPortal} from 'shared/ReactWorkTags';
24 +import {HostRoot, HostPortal, HostComponent} from 'shared/ReactWorkTags';
25
26 import {addTrappedEventListener} from './ReactDOMEventListener';
27 import getEventTarget from './getEventTarget';
@@ -305,3 +306,46 @@ export function attachElementListener(listener: ReactDOMListener): void {
306 export function detachElementListener(listener: ReactDOMListener): void {
307 // TODO
308 }
309 +
310 +export function accumulateTwoPhaseListeners(event: ReactSyntheticEvent): void {
311 + const phasedRegistrationNames = event.dispatchConfig.phasedRegistrationNames;
312 + if (phasedRegistrationNames == null) {
313 + return;
314 + }
315 + const {bubbled, captured} = phasedRegistrationNames;
316 + const dispatchListeners = [];
317 + const dispatchInstances = [];
318 + let node = event._targetInst;
319 + let hasListeners = false;
320 +
321 + // Accumulate all instances and listeners via the target -> root path.
322 + while (node !== null) {
323 + // We only care for listeners that are on HostComponents (i.e. <div>)
324 + if (node.tag === HostComponent) {
325 + // Standard React on* listeners, i.e. onClick prop
326 + const captureListener = getListener(node, captured);
327 + if (captureListener != null) {
328 + hasListeners = true;
329 + // Capture listeners/instances should go at the start, so we
330 + // unshift them to the start of the array.
331 + dispatchListeners.unshift(captureListener);
332 + dispatchInstances.unshift(node);
333 + }
334 + const bubbleListener = getListener(node, bubbled);
335 + if (bubbleListener != null) {
336 + hasListeners = true;
337 + // Bubble listeners/instances should go at the end, so we
338 + // push them to the end of the array.
339 + dispatchListeners.push(bubbleListener);
340 + dispatchInstances.push(node);
341 + }
342 + }
343 + node = node.return;
344 + }
345 + // To prevent allocation to the event unless we actually
346 + // have listeners we use the flag we would have set above.
347 + if (hasListeners) {
348 + event._dispatchListeners = dispatchListeners;
349 + event._dispatchInstances = dispatchInstances;
350 + }
351 +}
packages/react-dom/src/events/SelectEventPlugin.js
+2 -2
@@ -5,7 +5,6 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
8 import {canUseDOM} from 'shared/ExecutionEnvironment';
9 import SyntheticEvent from 'legacy-events/SyntheticEvent';
10 import isTextInputElement from 'shared/isTextInputElement';
@@ -27,6 +26,7 @@ import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
26 import {hasSelectionCapabilities} from '../client/ReactInputSelection';
27 import {DOCUMENT_NODE} from '../shared/HTMLNodeType';
28 import {isListeningToAllDependencies} from './DOMEventListenerMap';
29 +import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
30
31 const skipSelectionChangeEvent =
32 canUseDOM && 'documentMode' in document && document.documentMode <= 11;
@@ -135,7 +135,7 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
135 syntheticEvent.type = 'select';
136 syntheticEvent.target = activeElement;
137
138 - accumulateTwoPhaseDispatchesSingle(syntheticEvent);
138 + accumulateTwoPhaseListeners(syntheticEvent);
139
140 return syntheticEvent;
141 }
packages/react-dom/src/events/SimpleEventPlugin.js
+2 -2
@@ -16,7 +16,6 @@ import type {Fiber} from 'react-reconciler/src/ReactFiber';
16 import type {PluginModule} from 'legacy-events/PluginModuleType';
17 import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
18
19 -import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
19 import SyntheticEvent from 'legacy-events/SyntheticEvent';
20
21 import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes';
@@ -37,6 +36,7 @@ import SyntheticTransitionEvent from './SyntheticTransitionEvent';
36 import SyntheticUIEvent from './SyntheticUIEvent';
37 import SyntheticWheelEvent from './SyntheticWheelEvent';
38 import getEventCharCode from './getEventCharCode';
39 +import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
40
41 // Only used in DEV for exhaustiveness validation.
42 const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
@@ -191,7 +191,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
191 nativeEvent,
192 nativeEventTarget,
193 );
194 - accumulateTwoPhaseDispatchesSingle(event);
194 + accumulateTwoPhaseListeners(event);
195 return event;
196 },
197 };