Skip to content

Commit 80f8b0d

Browse files
authored
Add part of the event responder system for experimental event API (#15179)
* Add part of the event responder system
1 parent d03ac4b commit 80f8b0d

15 files changed

+593
-107
lines changed

packages/events/EventBatching.js

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
* @flow
7+
*/
8+
9+
import invariant from 'shared/invariant';
10+
import {rethrowCaughtError} from 'shared/ReactErrorUtils';
11+
12+
import type {ReactSyntheticEvent} from './ReactSyntheticEventType';
13+
import accumulateInto from './accumulateInto';
14+
import forEachAccumulated from './forEachAccumulated';
15+
import {executeDispatchesInOrder} from './EventPluginUtils';
16+
17+
/**
18+
* Internal queue of events that have accumulated their dispatches and are
19+
* waiting to have their dispatches executed.
20+
*/
21+
let eventQueue: ?(Array<ReactSyntheticEvent> | ReactSyntheticEvent) = null;
22+
23+
/**
24+
* Dispatches an event and releases it back into the pool, unless persistent.
25+
*
26+
* @param {?object} event Synthetic event to be dispatched.
27+
* @private
28+
*/
29+
const executeDispatchesAndRelease = function(event: ReactSyntheticEvent) {
30+
if (event) {
31+
executeDispatchesInOrder(event);
32+
33+
if (!event.isPersistent()) {
34+
event.constructor.release(event);
35+
}
36+
}
37+
};
38+
const executeDispatchesAndReleaseTopLevel = function(e) {
39+
return executeDispatchesAndRelease(e);
40+
};
41+
42+
export function runEventsInBatch(
43+
events: Array<ReactSyntheticEvent> | ReactSyntheticEvent | null,
44+
) {
45+
if (events !== null) {
46+
eventQueue = accumulateInto(eventQueue, events);
47+
}
48+
49+
// Set `eventQueue` to null before processing it so that we can tell if more
50+
// events get enqueued while processing.
51+
const processingEventQueue = eventQueue;
52+
eventQueue = null;
53+
54+
if (!processingEventQueue) {
55+
return;
56+
}
57+
58+
forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel);
59+
invariant(
60+
!eventQueue,
61+
'processEventQueue(): Additional events were enqueued while processing ' +
62+
'an event queue. Support for this has not yet been implemented.',
63+
);
64+
// This would be a good time to rethrow if any of the event handlers threw.
65+
rethrowCaughtError();
66+
}

packages/events/EventPluginHub.js

+5-60
Original file line numberDiff line numberDiff line change
@@ -6,52 +6,23 @@
66
* @flow
77
*/
88

9-
import {rethrowCaughtError} from 'shared/ReactErrorUtils';
109
import invariant from 'shared/invariant';
1110

1211
import {
1312
injectEventPluginOrder,
1413
injectEventPluginsByName,
1514
plugins,
1615
} from './EventPluginRegistry';
17-
import {
18-
executeDispatchesInOrder,
19-
getFiberCurrentPropsFromNode,
20-
} from './EventPluginUtils';
16+
import {getFiberCurrentPropsFromNode} from './EventPluginUtils';
2117
import accumulateInto from './accumulateInto';
22-
import forEachAccumulated from './forEachAccumulated';
18+
import {runEventsInBatch} from './EventBatching';
2319

2420
import type {PluginModule} from './PluginModuleType';
2521
import type {ReactSyntheticEvent} from './ReactSyntheticEventType';
2622
import type {Fiber} from 'react-reconciler/src/ReactFiber';
2723
import type {AnyNativeEvent} from './PluginModuleType';
2824
import type {TopLevelType} from './TopLevelEventTypes';
2925

30-
/**
31-
* Internal queue of events that have accumulated their dispatches and are
32-
* waiting to have their dispatches executed.
33-
*/
34-
let eventQueue: ?(Array<ReactSyntheticEvent> | ReactSyntheticEvent) = null;
35-
36-
/**
37-
* Dispatches an event and releases it back into the pool, unless persistent.
38-
*
39-
* @param {?object} event Synthetic event to be dispatched.
40-
* @private
41-
*/
42-
const executeDispatchesAndRelease = function(event: ReactSyntheticEvent) {
43-
if (event) {
44-
executeDispatchesInOrder(event);
45-
46-
if (!event.isPersistent()) {
47-
event.constructor.release(event);
48-
}
49-
}
50-
};
51-
const executeDispatchesAndReleaseTopLevel = function(e) {
52-
return executeDispatchesAndRelease(e);
53-
};
54-
5526
function isInteractive(tag) {
5627
return (
5728
tag === 'button' ||
@@ -158,7 +129,7 @@ export function getListener(inst: Fiber, registrationName: string) {
158129
* @return {*} An accumulation of synthetic events.
159130
* @internal
160131
*/
161-
function extractEvents(
132+
function extractPluginEvents(
162133
topLevelType: TopLevelType,
163134
targetInst: null | Fiber,
164135
nativeEvent: AnyNativeEvent,
@@ -183,39 +154,13 @@ function extractEvents(
183154
return events;
184155
}
185156

186-
export function runEventsInBatch(
187-
events: Array<ReactSyntheticEvent> | ReactSyntheticEvent | null,
188-
) {
189-
if (events !== null) {
190-
eventQueue = accumulateInto(eventQueue, events);
191-
}
192-
193-
// Set `eventQueue` to null before processing it so that we can tell if more
194-
// events get enqueued while processing.
195-
const processingEventQueue = eventQueue;
196-
eventQueue = null;
197-
198-
if (!processingEventQueue) {
199-
return;
200-
}
201-
202-
forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel);
203-
invariant(
204-
!eventQueue,
205-
'processEventQueue(): Additional events were enqueued while processing ' +
206-
'an event queue. Support for this has not yet been implemented.',
207-
);
208-
// This would be a good time to rethrow if any of the event handlers threw.
209-
rethrowCaughtError();
210-
}
211-
212-
export function runExtractedEventsInBatch(
157+
export function runExtractedPluginEventsInBatch(
213158
topLevelType: TopLevelType,
214159
targetInst: null | Fiber,
215160
nativeEvent: AnyNativeEvent,
216161
nativeEventTarget: EventTarget,
217162
) {
218-
const events = extractEvents(
163+
const events = extractPluginEvents(
219164
topLevelType,
220165
targetInst,
221166
nativeEvent,

packages/events/__tests__/ResponderEventPlugin-test.internal.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
const {HostComponent} = require('shared/ReactWorkTags');
1313

14-
let EventPluginHub;
14+
let EventBatching;
1515
let EventPluginUtils;
1616
let ResponderEventPlugin;
1717

@@ -321,7 +321,7 @@ const run = function(config, hierarchyConfig, nativeEventConfig) {
321321
// At this point the negotiation events have been dispatched as part of the
322322
// extraction process, but not the side effectful events. Below, we dispatch
323323
// side effectful events.
324-
EventPluginHub.runEventsInBatch(extractedEvents);
324+
EventBatching.runEventsInBatch(extractedEvents);
325325

326326
// Ensure that every event that declared an `order`, was actually dispatched.
327327
expect('number of events dispatched:' + runData.dispatchCount).toBe(
@@ -403,7 +403,7 @@ describe('ResponderEventPlugin', () => {
403403
jest.resetModules();
404404

405405
const ReactDOMUnstableNativeDependencies = require('react-dom/unstable-native-dependencies');
406-
EventPluginHub = require('events/EventPluginHub');
406+
EventBatching = require('events/EventBatching');
407407
EventPluginUtils = require('events/EventPluginUtils');
408408
ResponderEventPlugin =
409409
ReactDOMUnstableNativeDependencies.ResponderEventPlugin;

packages/react-dom/src/client/ReactDOM.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,8 @@ import {
4444
enqueueStateRestore,
4545
restoreStateIfNeeded,
4646
} from 'events/ReactControlledComponent';
47-
import {
48-
injection as EventPluginHubInjection,
49-
runEventsInBatch,
50-
} from 'events/EventPluginHub';
47+
import {injection as EventPluginHubInjection} from 'events/EventPluginHub';
48+
import {runEventsInBatch} from 'events/EventBatching';
5149
import {eventNameDispatchConfigs} from 'events/EventPluginRegistry';
5250
import {
5351
accumulateTwoPhaseDispatches,

packages/react-dom/src/client/ReactDOMHostConfig.js

+20-16
Original file line numberDiff line numberDiff line change
@@ -862,29 +862,33 @@ export function handleEventComponent(
862862
rootContainerInstance: Container,
863863
internalInstanceHandle: Object,
864864
): void {
865-
const rootElement = rootContainerInstance.ownerDocument;
866-
listenToEventResponderEvents(eventResponder, rootElement);
865+
if (enableEventAPI) {
866+
const rootElement = rootContainerInstance.ownerDocument;
867+
listenToEventResponderEvents(eventResponder, rootElement);
868+
}
867869
}
868870

869871
export function handleEventTarget(
870872
type: Symbol | number,
871873
props: Props,
872874
internalInstanceHandle: Object,
873875
): void {
874-
// Touch target hit slop handling
875-
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
876-
// Validates that there is a single element
877-
const element = getElementFromTouchHitTarget(internalInstanceHandle);
878-
if (element !== null) {
879-
// We update the event target state node to be that of the element.
880-
// We can then diff this entry to determine if we need to add the
881-
// hit slop element, or change the dimensions of the hit slop.
882-
const lastElement = internalInstanceHandle.stateNode;
883-
if (lastElement !== element) {
884-
internalInstanceHandle.stateNode = element;
885-
// TODO: Create the hit slop element and attach it to the element
886-
} else {
887-
// TODO: Diff the left, top, right, bottom props
876+
if (enableEventAPI) {
877+
// Touch target hit slop handling
878+
if (type === REACT_EVENT_TARGET_TOUCH_HIT) {
879+
// Validates that there is a single element
880+
const element = getElementFromTouchHitTarget(internalInstanceHandle);
881+
if (element !== null) {
882+
// We update the event target state node to be that of the element.
883+
// We can then diff this entry to determine if we need to add the
884+
// hit slop element, or change the dimensions of the hit slop.
885+
const lastElement = internalInstanceHandle.stateNode;
886+
if (lastElement !== element) {
887+
internalInstanceHandle.stateNode = element;
888+
// TODO: Create the hit slop element and attach it to the element
889+
} else {
890+
// TODO: Diff the left, top, right, bottom props
891+
}
888892
}
889893
}
890894
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import {runEventsInBatch} from 'events/EventPluginHub';
8+
import {runEventsInBatch} from 'events/EventBatching';
99
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
1010
import {enqueueStateRestore} from 'events/ReactControlledComponent';
1111
import {batchedUpdates} from 'events/ReactGenericBatching';

0 commit comments

Comments
 (0)