@samitouri / QOS-React / commits / 808f31af5c

Reduce the handleTopLevel() event code indirection (#11915)

* Refactor event emitters to reduce indirection * Remove unused handleTopLevel() injection * Rename handleTopLevel() to runExtractedEventsInBatch() and remove import indirection

Dan Abramov committed Jan 5, 2018 at 18:37 UTC 808f31af5cc571880058281c3ba1e1c69ce8aa5c
9 files changed +42 -86
packages/events/EventPluginHub.js
+22 -20
@@ -164,13 +164,13 @@ export function getListener(inst: Fiber, registrationName: string) {
164 * @return {*} An accumulation of synthetic events.
165 * @internal
166 */
167 -export function extractEvents(
167 +function extractEvents(
168 topLevelType: string,
169 targetInst: Fiber,
170 nativeEvent: AnyNativeEvent,
171 nativeEventTarget: EventTarget,
172 -) {
173 - let events;
172 +): Array<ReactSyntheticEvent> | ReactSyntheticEvent | null {
173 + let events = null;
174 for (let i = 0; i < plugins.length; i++) {
175 // Not every plugin in the ordering may be loaded at runtime.
176 const possiblePlugin: PluginModule<AnyNativeEvent> = plugins[i];
@@ -189,27 +189,14 @@ export function extractEvents(
189 return events;
190 }
191
192 -/**
193 - * Enqueues a synthetic event that should be dispatched when
194 - * `processEventQueue` is invoked.
195 - *
196 - * @param {*} events An accumulation of synthetic events.
197 - * @internal
198 - */
199 -export function enqueueEvents(
200 - events: Array<ReactSyntheticEvent> | ReactSyntheticEvent,
192 +export function runEventsInBatch(
193 + events: Array<ReactSyntheticEvent> | ReactSyntheticEvent | null,
194 + simulated: boolean,
195 ) {
202 - if (events) {
196 + if (events !== null) {
197 eventQueue = accumulateInto(eventQueue, events);
198 }
205 -}
199
207 -/**
208 - * Dispatches all synthetic events on the event queue.
209 - *
210 - * @internal
211 - */
212 -export function processEventQueue(simulated: boolean) {
200 // Set `eventQueue` to null before processing it so that we can tell if more
201 // events get enqueued while processing.
202 const processingEventQueue = eventQueue;
@@ -238,3 +225,18 @@ export function processEventQueue(simulated: boolean) {
225 // This would be a good time to rethrow if any of the event handlers threw.
226 ReactErrorUtils.rethrowCaughtError();
227 }
228 +
229 +export function runExtractedEventsInBatch(
230 + topLevelType: string,
231 + targetInst: Fiber,
232 + nativeEvent: AnyNativeEvent,
233 + nativeEventTarget: EventTarget,
234 +) {
235 + const events = extractEvents(
236 + topLevelType,
237 + targetInst,
238 + nativeEvent,
239 + nativeEventTarget,
240 + );
241 + runEventsInBatch(events, false);
242 +}
packages/events/ReactEventEmitterMixin.js deleted
-36
@@ -1,36 +0,0 @@
1 -/**
2 - * Copyright (c) 2013-present, Facebook, Inc.
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 -
8 -import {
9 - enqueueEvents,
10 - processEventQueue,
11 - extractEvents,
12 -} from './EventPluginHub';
13 -
14 -function runEventQueueInBatch(events) {
15 - enqueueEvents(events);
16 - processEventQueue(false);
17 -}
18 -
19 -/**
20 - * Streams a fired top-level event to `EventPluginHub` where plugins have the
21 - * opportunity to create `ReactEvent`s to be dispatched.
22 - */
23 -export function handleTopLevel(
24 - topLevelType,
25 - targetInst,
26 - nativeEvent,
27 - nativeEventTarget,
28 -) {
29 - const events = extractEvents(
30 - topLevelType,
31 - targetInst,
32 - nativeEvent,
33 - nativeEventTarget,
34 - );
35 - runEventQueueInBatch(events);
36 -}
packages/events/__tests__/ResponderEventPlugin-test.internal.js
+1 -2
@@ -312,8 +312,7 @@ const run = function(config, hierarchyConfig, nativeEventConfig) {
312 // At this point the negotiation events have been dispatched as part of the
313 // extraction process, but not the side effectful events. Below, we dispatch
314 // side effectful events.
315 - EventPluginHub.enqueueEvents(extractedEvents);
316 - EventPluginHub.processEventQueue(true);
315 + EventPluginHub.runEventsInBatch(extractedEvents, true);
316
317 // Ensure that every event that declared an `order`, was actually dispatched.
318 expect('number of events dispatched:' + runData.dispatchCount).toBe(
packages/react-dom/src/client/ReactDOMClientInjection.js
-4
@@ -13,13 +13,9 @@ import BeforeInputEventPlugin from '../events/BeforeInputEventPlugin';
13 import ChangeEventPlugin from '../events/ChangeEventPlugin';
14 import DOMEventPluginOrder from '../events/DOMEventPluginOrder';
15 import EnterLeaveEventPlugin from '../events/EnterLeaveEventPlugin';
16 -import {handleTopLevel} from '../events/ReactBrowserEventEmitter';
17 -import {setHandleTopLevel} from '../events/ReactDOMEventListener';
16 import SelectEventPlugin from '../events/SelectEventPlugin';
17 import SimpleEventPlugin from '../events/SimpleEventPlugin';
18
21 -setHandleTopLevel(handleTopLevel);
22 -
19 /**
20 * Inject modules for resolving DOM hierarchy and plugin ordering.
21 */
packages/react-dom/src/events/ChangeEventPlugin.js
+2 -3
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {enqueueEvents, processEventQueue} from 'events/EventPluginHub';
8 +import * as EventPluginHub from 'events/EventPluginHub';
9 import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
10 import {enqueueStateRestore} from 'events/ReactControlledComponent';
11 import {batchedUpdates} from 'events/ReactGenericBatching';
@@ -89,8 +89,7 @@ function manualDispatchChangeEvent(nativeEvent) {
89 }
90
91 function runEventInBatch(event) {
92 - enqueueEvents(event);
93 - processEventQueue(false);
92 + EventPluginHub.runEventsInBatch(event, false);
93 }
94
95 function getInstIfValueChanged(targetInst) {
packages/react-dom/src/events/ReactBrowserEventEmitter.js
-3
@@ -6,7 +6,6 @@
6 */
7
8 import {registrationNameDependencies} from 'events/EventPluginRegistry';
9 -
9 import {
10 setEnabled,
11 isEnabled,
@@ -16,8 +15,6 @@ import {
15 import isEventSupported from './isEventSupported';
16 import BrowserEventConstants from './BrowserEventConstants';
17
19 -export * from 'events/ReactEventEmitterMixin';
20 -
18 const {topLevelTypes} = BrowserEventConstants;
19
20 /**
packages/react-dom/src/events/ReactDOMEventListener.js
+4 -8
@@ -6,6 +6,7 @@
6 */
7
8 import {batchedUpdates} from 'events/ReactGenericBatching';
9 +import {runExtractedEventsInBatch} from 'events/EventPluginHub';
10 import {isFiberMounted} from 'react-reconciler/reflection';
11 import {HostRoot} from 'shared/ReactTypeOfWork';
12
@@ -62,7 +63,7 @@ function releaseTopLevelCallbackBookKeeping(instance) {
63 }
64 }
65
65 -function handleTopLevelImpl(bookKeeping) {
66 +function handleTopLevel(bookKeeping) {
67 let targetInst = bookKeeping.targetInst;
68
69 // Loop through the hierarchy, in case there's any nested components.
@@ -85,7 +86,7 @@ function handleTopLevelImpl(bookKeeping) {
86
87 for (let i = 0; i < bookKeeping.ancestors.length; i++) {
88 targetInst = bookKeeping.ancestors[i];
88 - _handleTopLevel(
89 + runExtractedEventsInBatch(
90 bookKeeping.topLevelType,
91 targetInst,
92 bookKeeping.nativeEvent,
@@ -96,11 +97,6 @@ function handleTopLevelImpl(bookKeeping) {
97
98 // TODO: can we stop exporting these?
99 export let _enabled = true;
99 -export let _handleTopLevel: null;
100 -
101 -export function setHandleTopLevel(handleTopLevel) {
102 - _handleTopLevel = handleTopLevel;
103 -}
100
101 export function setEnabled(enabled) {
102 _enabled = !!enabled;
@@ -180,7 +176,7 @@ export function dispatchEvent(topLevelType, nativeEvent) {
176 try {
177 // Event queue being processed in the same cycle allows
178 // `preventDefault`.
183 - batchedUpdates(handleTopLevelImpl, bookKeeping);
179 + batchedUpdates(handleTopLevel, bookKeeping);
180 } finally {
181 releaseTopLevelCallbackBookKeeping(bookKeeping);
182 }
packages/react-dom/src/test-utils/ReactTestUtils.js
+1 -3
@@ -388,9 +388,7 @@ function makeSimulator(eventType) {
388 // Normally extractEvent enqueues a state restore, but we'll just always
389 // do that since we we're by-passing it here.
390 ReactControlledComponent.enqueueStateRestore(domNode);
391 -
392 - EventPluginHub.enqueueEvents(event);
393 - EventPluginHub.processEventQueue(true);
391 + EventPluginHub.runEventsInBatch(event, true);
392 });
393 };
394 }
packages/react-native-renderer/src/ReactNativeEventEmitter.js
+12 -7
@@ -7,16 +7,16 @@
7 * @flow
8 */
9
10 -import {getListener} from 'events/EventPluginHub';
10 +import {getListener, runExtractedEventsInBatch} from 'events/EventPluginHub';
11 import {registrationNameModules} from 'events/EventPluginRegistry';
12 import {batchedUpdates} from 'events/ReactGenericBatching';
13 -import {handleTopLevel} from 'events/ReactEventEmitterMixin';
13 import warning from 'fbjs/lib/warning';
14
15 import {getInstanceFromNode} from './ReactNativeComponentTree';
16 import ReactNativeTagHandles from './ReactNativeTagHandles';
17
19 -export * from 'events/ReactEventEmitterMixin';
18 +import type {AnyNativeEvent} from 'events/PluginModuleType';
19 +
20 export {getListener, registrationNameModules as registrationNames};
21
22 /**
@@ -25,7 +25,7 @@ export {getListener, registrationNameModules as registrationNames};
25 */
26
27 // Shared default empty native event - conserve memory.
28 -const EMPTY_NATIVE_EVENT = {};
28 +const EMPTY_NATIVE_EVENT = (({}: any): AnyNativeEvent);
29
30 /**
31 * Selects a subsequence of `Touch`es, without destroying `touches`.
@@ -90,12 +90,17 @@ const removeTouchesAtIndices = function(
90 export function _receiveRootNodeIDEvent(
91 rootNodeID: number,
92 topLevelType: string,
93 - nativeEventParam: ?Object,
93 + nativeEventParam: ?AnyNativeEvent,
94 ) {
95 const nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
96 const inst = getInstanceFromNode(rootNodeID);
97 batchedUpdates(function() {
98 - handleTopLevel(topLevelType, inst, nativeEvent, nativeEvent.target);
98 + runExtractedEventsInBatch(
99 + topLevelType,
100 + inst,
101 + nativeEvent,
102 + nativeEvent.target,
103 + );
104 });
105 // React Native doesn't use ReactControlledComponent but if it did, here's
106 // where it would do it.
@@ -111,7 +116,7 @@ export function _receiveRootNodeIDEvent(
116 export function receiveEvent(
117 rootNodeID: number,
118 topLevelType: string,
114 - nativeEventParam: Object,
119 + nativeEventParam: AnyNativeEvent,
120 ) {
121 _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam);
122 }