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
}