Skip to content

Commit 85d9655

Browse files
authored
[react-dom] Refactor event priority handling to its own module (#17678)
1 parent 3e09677 commit 85d9655

File tree

3 files changed

+202
-183
lines changed

3 files changed

+202
-183
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
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 {EventPriority} from 'shared/ReactTypes';
11+
import type {
12+
TopLevelType,
13+
DOMTopLevelEventType,
14+
} from 'legacy-events/TopLevelEventTypes';
15+
import type {DispatchConfig} from 'legacy-events/ReactSyntheticEventType';
16+
17+
import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes';
18+
import {
19+
DiscreteEvent,
20+
UserBlockingEvent,
21+
ContinuousEvent,
22+
} from 'shared/ReactTypes';
23+
24+
// Needed for SimpleEventPlugin, rather than
25+
// do it in two places, which duplicates logic
26+
// and increases the bundle size, we do it all
27+
// here once. If we remove or refactor the
28+
// SimpleEventPlugin, we should also remove or
29+
// update the below line.
30+
export const simpleEventPluginEventTypes = {};
31+
32+
export const topLevelEventsToDispatchConfig: Map<
33+
TopLevelType,
34+
DispatchConfig,
35+
> = new Map();
36+
37+
const eventPriorities = new Map();
38+
39+
// We store all the DOMTopLevelEventTypes and their React Types in pairs of two.
40+
// Furthermore, we ignore prettier so we can keep the formatting sane.
41+
42+
// prettier-ignore
43+
const discreteEvents = [
44+
DOMTopLevelEventTypes.TOP_BLUR, 'blur',
45+
DOMTopLevelEventTypes.TOP_CANCEL, 'cancel',
46+
DOMTopLevelEventTypes.TOP_CLICK, 'click',
47+
DOMTopLevelEventTypes.TOP_CLOSE, 'close',
48+
DOMTopLevelEventTypes.TOP_CONTEXT_MENU, 'contextMenu',
49+
DOMTopLevelEventTypes.TOP_COPY, 'copy',
50+
DOMTopLevelEventTypes.TOP_CUT, 'cut',
51+
DOMTopLevelEventTypes.TOP_AUX_CLICK, 'auxClick',
52+
DOMTopLevelEventTypes.TOP_DOUBLE_CLICK, 'doubleClick',
53+
DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd',
54+
DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart',
55+
DOMTopLevelEventTypes.TOP_DROP, 'drop',
56+
DOMTopLevelEventTypes.TOP_FOCUS, 'focus',
57+
DOMTopLevelEventTypes.TOP_INPUT, 'input',
58+
DOMTopLevelEventTypes.TOP_INVALID, 'invalid',
59+
DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown',
60+
DOMTopLevelEventTypes.TOP_KEY_PRESS, 'keyPress',
61+
DOMTopLevelEventTypes.TOP_KEY_UP, 'keyUp',
62+
DOMTopLevelEventTypes.TOP_MOUSE_DOWN, 'mouseDown',
63+
DOMTopLevelEventTypes.TOP_MOUSE_UP, 'mouseUp',
64+
DOMTopLevelEventTypes.TOP_PASTE, 'paste',
65+
DOMTopLevelEventTypes.TOP_PAUSE, 'pause',
66+
DOMTopLevelEventTypes.TOP_PLAY, 'play',
67+
DOMTopLevelEventTypes.TOP_POINTER_CANCEL, 'pointerCancel',
68+
DOMTopLevelEventTypes.TOP_POINTER_DOWN, 'pointerDown',
69+
DOMTopLevelEventTypes.TOP_POINTER_UP, 'pointerUp',
70+
DOMTopLevelEventTypes.TOP_RATE_CHANGE, 'rateChange',
71+
DOMTopLevelEventTypes.TOP_RESET, 'reset',
72+
DOMTopLevelEventTypes.TOP_SEEKED, 'seeked',
73+
DOMTopLevelEventTypes.TOP_SUBMIT, 'submit',
74+
DOMTopLevelEventTypes.TOP_TOUCH_CANCEL, 'touchCancel',
75+
DOMTopLevelEventTypes.TOP_TOUCH_END, 'touchEnd',
76+
DOMTopLevelEventTypes.TOP_TOUCH_START, 'touchStart',
77+
DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, 'volumeChange',
78+
];
79+
80+
// prettier-ignore
81+
const userBlockingEvents = [
82+
DOMTopLevelEventTypes.TOP_DRAG, 'drag',
83+
DOMTopLevelEventTypes.TOP_DRAG_ENTER, 'dragEnter',
84+
DOMTopLevelEventTypes.TOP_DRAG_EXIT, 'dragExit',
85+
DOMTopLevelEventTypes.TOP_DRAG_LEAVE, 'dragLeave',
86+
DOMTopLevelEventTypes.TOP_DRAG_OVER, 'dragOver',
87+
DOMTopLevelEventTypes.TOP_MOUSE_MOVE, 'mouseMove',
88+
DOMTopLevelEventTypes.TOP_MOUSE_OUT, 'mouseOut',
89+
DOMTopLevelEventTypes.TOP_MOUSE_OVER, 'mouseOver',
90+
DOMTopLevelEventTypes.TOP_POINTER_MOVE, 'pointerMove',
91+
DOMTopLevelEventTypes.TOP_POINTER_OUT, 'pointerOut',
92+
DOMTopLevelEventTypes.TOP_POINTER_OVER, 'pointerOver',
93+
DOMTopLevelEventTypes.TOP_SCROLL, 'scroll',
94+
DOMTopLevelEventTypes.TOP_TOGGLE, 'toggle',
95+
DOMTopLevelEventTypes.TOP_TOUCH_MOVE, 'touchMove',
96+
DOMTopLevelEventTypes.TOP_WHEEL, 'wheel',
97+
];
98+
99+
// prettier-ignore
100+
const continuousEvents = [
101+
DOMTopLevelEventTypes.TOP_ABORT, 'abort',
102+
DOMTopLevelEventTypes.TOP_ANIMATION_END, 'animationEnd',
103+
DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION, 'animationIteration',
104+
DOMTopLevelEventTypes.TOP_ANIMATION_START, 'animationStart',
105+
DOMTopLevelEventTypes.TOP_CAN_PLAY, 'canPlay',
106+
DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, 'canPlayThrough',
107+
DOMTopLevelEventTypes.TOP_DURATION_CHANGE, 'durationChange',
108+
DOMTopLevelEventTypes.TOP_EMPTIED, 'emptied',
109+
DOMTopLevelEventTypes.TOP_ENCRYPTED, 'encrypted',
110+
DOMTopLevelEventTypes.TOP_ENDED, 'ended',
111+
DOMTopLevelEventTypes.TOP_ERROR, 'error',
112+
DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE, 'gotPointerCapture',
113+
DOMTopLevelEventTypes.TOP_LOAD, 'load',
114+
DOMTopLevelEventTypes.TOP_LOADED_DATA, 'loadedData',
115+
DOMTopLevelEventTypes.TOP_LOADED_METADATA, 'loadedMetadata',
116+
DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart',
117+
DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE, 'lostPointerCapture',
118+
DOMTopLevelEventTypes.TOP_PLAYING, 'playing',
119+
DOMTopLevelEventTypes.TOP_PROGRESS, 'progress',
120+
DOMTopLevelEventTypes.TOP_SEEKING, 'seeking',
121+
DOMTopLevelEventTypes.TOP_STALLED, 'stalled',
122+
DOMTopLevelEventTypes.TOP_SUSPEND, 'suspend',
123+
DOMTopLevelEventTypes.TOP_TIME_UPDATE, 'timeUpdate',
124+
DOMTopLevelEventTypes.TOP_TRANSITION_END, 'transitionEnd',
125+
DOMTopLevelEventTypes.TOP_WAITING, 'waiting',
126+
];
127+
128+
/**
129+
* Turns
130+
* ['abort', ...]
131+
* into
132+
* eventTypes = {
133+
* 'abort': {
134+
* phasedRegistrationNames: {
135+
* bubbled: 'onAbort',
136+
* captured: 'onAbortCapture',
137+
* },
138+
* dependencies: [TOP_ABORT],
139+
* },
140+
* ...
141+
* };
142+
* topLevelEventsToDispatchConfig = new Map([
143+
* [TOP_ABORT, { sameConfig }],
144+
* ]);
145+
*/
146+
147+
function processTopEventTypesByPriority(
148+
eventTypes: Array<DOMTopLevelEventType | string>,
149+
priority: EventPriority,
150+
): void {
151+
// As the event types are in pairs of two, we need to iterate
152+
// through in twos. The events are in pairs of two to save code
153+
// and improve init perf of processing this array, as it will
154+
// result in far fewer object allocations and property accesses
155+
// if we only use three arrays to process all the categories of
156+
// instead of tuples.
157+
for (let i = 0; i < eventTypes.length; i += 2) {
158+
const topEvent = ((eventTypes[i]: any): DOMTopLevelEventType);
159+
const event = ((eventTypes[i + 1]: any): string);
160+
const capitalizedEvent = event[0].toUpperCase() + event.slice(1);
161+
const onEvent = 'on' + capitalizedEvent;
162+
163+
const config = {
164+
phasedRegistrationNames: {
165+
bubbled: onEvent,
166+
captured: onEvent + 'Capture',
167+
},
168+
dependencies: [topEvent],
169+
eventPriority: priority,
170+
};
171+
eventPriorities.set(topEvent, priority);
172+
topLevelEventsToDispatchConfig.set(topEvent, config);
173+
simpleEventPluginEventTypes[event] = config;
174+
}
175+
}
176+
177+
processTopEventTypesByPriority(discreteEvents, DiscreteEvent);
178+
processTopEventTypesByPriority(userBlockingEvents, UserBlockingEvent);
179+
processTopEventTypesByPriority(continuousEvents, ContinuousEvent);
180+
181+
export function getEventPriorityForPluginSystem(
182+
topLevelType: TopLevelType,
183+
): EventPriority {
184+
const priority = eventPriorities.get(topLevelType);
185+
// Default to a ContinuousEvent. Note: we might
186+
// want to warn if we can't detect the priority
187+
// for the event.
188+
return priority === undefined ? ContinuousEvent : priority;
189+
}

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ import {
5959
} from './EventListener';
6060
import getEventTarget from './getEventTarget';
6161
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
62-
import SimpleEventPlugin from './SimpleEventPlugin';
6362
import {getRawEventName} from './DOMTopLevelEventTypes';
6463
import {passiveBrowserEventsSupported} from './checkPassiveEvents';
6564

@@ -69,14 +68,13 @@ import {
6968
ContinuousEvent,
7069
DiscreteEvent,
7170
} from 'shared/ReactTypes';
71+
import {getEventPriorityForPluginSystem} from './DOMEventProperties';
7272

7373
const {
7474
unstable_UserBlockingPriority: UserBlockingPriority,
7575
unstable_runWithPriority: runWithPriority,
7676
} = Scheduler;
7777

78-
const {getEventPriority} = SimpleEventPlugin;
79-
8078
const CALLBACK_BOOKKEEPING_POOL_SIZE = 10;
8179
const callbackBookkeepingPool = [];
8280

@@ -280,7 +278,7 @@ function trapEventForPluginEventSystem(
280278
capture: boolean,
281279
): void {
282280
let listener;
283-
switch (getEventPriority(topLevelType)) {
281+
switch (getEventPriorityForPluginSystem(topLevelType)) {
284282
case DiscreteEvent:
285283
listener = dispatchDiscreteEvent.bind(
286284
null,

0 commit comments

Comments
 (0)