diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index faa2e9a03f..3a6e9a0e31 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -8,7 +8,7 @@ */ import { - registrationNames, + registrationNameDependencies, possibleRegistrationNames, } from '../events/EventPluginRegistry'; import {canUseDOM} from 'shared/ExecutionEnvironment'; @@ -133,7 +133,7 @@ if (__DEV__) { validateARIAProperties(type, props); validateInputProperties(type, props); validateUnknownProperties(type, props, { - registrationNames, + registrationNameDependencies, possibleRegistrationNames, }); }; @@ -356,7 +356,7 @@ function setInitialDOMProperties( // We could have excluded it in the property list instead of // adding a special case here, but then it wouldn't be emitted // on server rendering (but we *do* want to emit it in SSR). - } else if (registrationNames.hasOwnProperty(propKey)) { + } else if (registrationNameDependencies.hasOwnProperty(propKey)) { if (nextProp != null) { if (__DEV__ && typeof nextProp !== 'function') { warnForInvalidEventListener(propKey, nextProp); @@ -694,7 +694,7 @@ export function diffProperties( // Noop } else if (propKey === AUTOFOCUS) { // Noop. It doesn't work on updates anyway. - } else if (registrationNames.hasOwnProperty(propKey)) { + } else if (registrationNameDependencies.hasOwnProperty(propKey)) { // This is a special case. If any listener updates we need to ensure // that the "current" fiber pointer gets updated so we need a commit // to update this element. @@ -781,7 +781,7 @@ export function diffProperties( propKey === SUPPRESS_HYDRATION_WARNING ) { // Noop - } else if (registrationNames.hasOwnProperty(propKey)) { + } else if (registrationNameDependencies.hasOwnProperty(propKey)) { if (nextProp != null) { // We eagerly listen to this even though we haven't committed yet. if (__DEV__ && typeof nextProp !== 'function') { @@ -978,7 +978,7 @@ export function diffHydratedProperties( updatePayload = [CHILDREN, '' + nextProp]; } } - } else if (registrationNames.hasOwnProperty(propKey)) { + } else if (registrationNameDependencies.hasOwnProperty(propKey)) { if (nextProp != null) { if (__DEV__ && typeof nextProp !== 'function') { warnForInvalidEventListener(propKey, nextProp); diff --git a/packages/react-dom/src/events/DOMEventProperties.js b/packages/react-dom/src/events/DOMEventProperties.js index 47de3fd9e8..97e34c0a7f 100644 --- a/packages/react-dom/src/events/DOMEventProperties.js +++ b/packages/react-dom/src/events/DOMEventProperties.js @@ -13,10 +13,6 @@ import type { DOMTopLevelEventType, } from '../events/TopLevelEventTypes'; import type {EventTypes} from '../events/PluginModuleType'; -import type { - DispatchConfig, - CustomDispatchConfig, -} from '../events/ReactSyntheticEventType'; import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes'; import { @@ -35,9 +31,9 @@ import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags'; // update the below line. export const simpleEventPluginEventTypes: EventTypes = {}; -export const topLevelEventsToDispatchConfig: Map< +export const topLevelEventsToReactNames: Map< TopLevelType, - DispatchConfig | CustomDispatchConfig, + string | null, > = new Map(); const eventPriorities = new Map(); @@ -167,8 +163,8 @@ const continuousPairsForSimpleEventPlugin = [ * }, * ... * }; - * topLevelEventsToDispatchConfig = new Map([ - * [TOP_ABORT, { sameConfig }], + * topLevelEventsToReactNames = new Map([ + * [TOP_ABORT, 'onAbort'], * ]); */ @@ -197,7 +193,7 @@ function processSimpleEventPluginPairsByPriority( eventPriority: priority, }; eventPriorities.set(topEvent, priority); - topLevelEventsToDispatchConfig.set(topEvent, config); + topLevelEventsToReactNames.set(topEvent, onEvent); simpleEventPluginEventTypes[event] = config; } } diff --git a/packages/react-dom/src/events/DOMModernPluginEventSystem.js b/packages/react-dom/src/events/DOMModernPluginEventSystem.js index 69669306f8..ce50157b11 100644 --- a/packages/react-dom/src/events/DOMModernPluginEventSystem.js +++ b/packages/react-dom/src/events/DOMModernPluginEventSystem.js @@ -16,10 +16,7 @@ import type { DispatchQueueItemPhase, DispatchQueueItemPhaseEntry, } from './PluginModuleType'; -import type { - ReactSyntheticEvent, - CustomDispatchConfig, -} from './ReactSyntheticEventType'; +import type {ReactSyntheticEvent} from './ReactSyntheticEventType'; import type { ElementListenerMap, ElementListenerMapEntry, @@ -113,7 +110,7 @@ import { addEventCaptureListenerWithPassiveFlag, } from './EventListener'; import {removeTrappedEventListener} from './DeprecatedDOMEventResponderSystem'; -import {topLevelEventsToDispatchConfig} from './DOMEventProperties'; +import {topLevelEventsToReactNames} from './DOMEventProperties'; import * as ModernBeforeInputEventPlugin from './plugins/ModernBeforeInputEventPlugin'; import * as ModernChangeEventPlugin from './plugins/ModernChangeEventPlugin'; import * as ModernEnterLeaveEventPlugin from './plugins/ModernEnterLeaveEventPlugin'; @@ -223,14 +220,6 @@ if (enableCreateEventHandleAPI) { capturePhaseEvents.add(TOP_AFTER_BLUR); } -const emptyDispatchConfigForCustomEvents: CustomDispatchConfig = { - customEvent: true, - phasedRegistrationNames: { - bubbled: null, - captured: null, - }, -}; - function executeDispatch( event: ReactSyntheticEvent, listener: Function, @@ -639,11 +628,11 @@ export function accumulateTwoPhaseListeners( event: ReactSyntheticEvent, accumulateEventHandleListeners?: boolean, ): void { - const phasedRegistrationNames = event.dispatchConfig.phasedRegistrationNames; + const bubbled = event._reactName; + const captured = bubbled !== null ? bubbled + 'Capture' : null; const capturePhase: DispatchQueueItemPhase = []; const bubblePhase: DispatchQueueItemPhase = []; - const {bubbled, captured} = phasedRegistrationNames; // If we are not handling EventTarget only phase, then we're doing the // usual two phase accumulation using the React fiber tree to pick up // all relevant useEvent and on* prop events. @@ -826,7 +815,7 @@ function accumulateEnterLeaveListenersForEvent( common: Fiber | null, capture: boolean, ): void { - const registrationName = event.dispatchConfig.registrationName; + const registrationName = event._reactName; if (registrationName === undefined) { return; } @@ -944,17 +933,14 @@ export function accumulateEventTargetListeners( } export function addEventTypeToDispatchConfig(type: DOMTopLevelEventType): void { - const dispatchConfig = topLevelEventsToDispatchConfig.get(type); - // If we don't have a dispatchConfig, then we're dealing with + const reactName = topLevelEventsToReactNames.get(type); + // If we don't have a reactName, then we're dealing with // an event type that React does not know about (i.e. a custom event). // We need to register an event config for this or the SimpleEventPlugin // will not appropriately provide a SyntheticEvent, so we use out empty // dispatch config for custom events. - if (dispatchConfig === undefined) { - topLevelEventsToDispatchConfig.set( - type, - emptyDispatchConfigForCustomEvents, - ); + if (reactName === undefined) { + topLevelEventsToReactNames.set(type, null); } } diff --git a/packages/react-dom/src/events/EventPluginRegistry.js b/packages/react-dom/src/events/EventPluginRegistry.js index d53fa43964..8876b89218 100644 --- a/packages/react-dom/src/events/EventPluginRegistry.js +++ b/packages/react-dom/src/events/EventPluginRegistry.js @@ -10,13 +10,6 @@ import type {TopLevelType} from './TopLevelEventTypes'; import type {EventTypes} from './PluginModuleType'; -import invariant from 'shared/invariant'; - -/** - * Mapping from registration name to plugin module - */ -export const registrationNames = {}; - /** * Mapping from registration name to event name */ @@ -62,13 +55,16 @@ function publishRegistrationName( registrationName: string, dependencies: ?Array, ): void { - invariant( - !registrationNames[registrationName], - 'EventPluginRegistry: More than one plugin attempted to publish the same ' + - 'registration name, `%s`.', - registrationName, - ); - registrationNames[registrationName] = true; + if (__DEV__) { + if (registrationNameDependencies[registrationName]) { + console.error( + 'EventPluginRegistry: More than one plugin attempted to publish the same ' + + 'registration name, `%s`.', + registrationName, + ); + } + } + registrationNameDependencies[registrationName] = dependencies; if (__DEV__) { diff --git a/packages/react-dom/src/events/ReactSyntheticEventType.js b/packages/react-dom/src/events/ReactSyntheticEventType.js index a82d84cce4..1903a93411 100644 --- a/packages/react-dom/src/events/ReactSyntheticEventType.js +++ b/packages/react-dom/src/events/ReactSyntheticEventType.js @@ -22,21 +22,12 @@ export type DispatchConfig = {| eventPriority?: EventPriority, |}; -export type CustomDispatchConfig = {| - phasedRegistrationNames: {| - bubbled: null, - captured: null, - |}, - registrationName?: string, - customEvent: true, -|}; - export type ReactSyntheticEvent = {| - dispatchConfig: DispatchConfig | CustomDispatchConfig, isPersistent: () => boolean, isPropagationStopped: () => boolean, _dispatchInstances?: null | Array | Fiber, _dispatchListeners?: null | Array | Function, + _reactName: string, _targetInst: Fiber, type: string, currentTarget: null | EventTarget, diff --git a/packages/react-dom/src/events/SyntheticEvent.js b/packages/react-dom/src/events/SyntheticEvent.js index 950fee5942..a0394195e1 100644 --- a/packages/react-dom/src/events/SyntheticEvent.js +++ b/packages/react-dom/src/events/SyntheticEvent.js @@ -48,19 +48,9 @@ function functionThatReturnsFalse() { * Synthetic events (and subclasses) implement the DOM Level 3 Events API by * normalizing browser quirks. Subclasses do not necessarily have to implement a * DOM interface; custom application-specific events can also subclass this. - * - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {*} targetInst Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @param {DOMEventTarget} nativeEventTarget Target node. */ -function SyntheticEvent( - dispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget, -) { - this.dispatchConfig = dispatchConfig; +function SyntheticEvent(reactName, targetInst, nativeEvent, nativeEventTarget) { + this._reactName = reactName; this._targetInst = targetInst; this.nativeEvent = nativeEvent; diff --git a/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js b/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js index cba864298a..f152f616c0 100644 --- a/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js @@ -140,11 +140,11 @@ function isKeypressCommand(nativeEvent) { function getCompositionEventType(topLevelType) { switch (topLevelType) { case TOP_COMPOSITION_START: - return eventTypes.compositionStart; + return 'onCompositionStart'; case TOP_COMPOSITION_END: - return eventTypes.compositionEnd; + return 'onCompositionEnd'; case TOP_COMPOSITION_UPDATE: - return eventTypes.compositionUpdate; + return 'onCompositionUpdate'; } } @@ -237,10 +237,10 @@ function extractCompositionEvent( eventType = getCompositionEventType(topLevelType); } else if (!isComposing) { if (isFallbackCompositionStart(topLevelType, nativeEvent)) { - eventType = eventTypes.compositionStart; + eventType = 'onCompositionStart'; } } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { - eventType = eventTypes.compositionEnd; + eventType = 'onCompositionEnd'; } if (!eventType) { @@ -250,9 +250,9 @@ function extractCompositionEvent( if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { // The current composition is stored statically and must not be // overwritten while composition continues. - if (!isComposing && eventType === eventTypes.compositionStart) { + if (!isComposing && eventType === 'onCompositionStart') { isComposing = FallbackCompositionStateInitialize(nativeEventTarget); - } else if (eventType === eventTypes.compositionEnd) { + } else if (eventType === 'onCompositionEnd') { if (isComposing) { fallbackData = FallbackCompositionStateGetData(); } @@ -430,7 +430,7 @@ function extractBeforeInputEvent( } const event = new SyntheticInputEvent( - eventTypes.beforeInput, + 'onBeforeInput', null, nativeEvent, nativeEventTarget, diff --git a/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js b/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js index 706d296c38..4d2d5a26cc 100644 --- a/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js @@ -64,12 +64,7 @@ function createAndAccumulateChangeEvent( nativeEvent, target, ) { - const event = new SyntheticEvent( - eventTypes.change, - null, - nativeEvent, - target, - ); + const event = new SyntheticEvent('onChange', null, nativeEvent, target); event.type = 'change'; // Flag this event loop as needing state restore. enqueueStateRestore(((target: any): Node)); diff --git a/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js b/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js index 063a4c5947..1fa7c80a9c 100644 --- a/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js @@ -126,16 +126,16 @@ function extractEvents( if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) { eventInterface = SyntheticMouseEvent; - leaveEventType = eventTypes.mouseLeave; - enterEventType = eventTypes.mouseEnter; + leaveEventType = 'onMouseLeave'; + enterEventType = 'onMouseEnter'; eventTypePrefix = 'mouse'; } else if ( topLevelType === TOP_POINTER_OUT || topLevelType === TOP_POINTER_OVER ) { eventInterface = SyntheticPointerEvent; - leaveEventType = eventTypes.pointerLeave; - enterEventType = eventTypes.pointerEnter; + leaveEventType = 'onPointerLeave'; + enterEventType = 'onPointerEnter'; eventTypePrefix = 'pointer'; } diff --git a/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js b/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js index d907c71b75..f066f06b82 100644 --- a/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js @@ -133,7 +133,7 @@ function constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) { lastSelection = currentSelection; const syntheticEvent = new SyntheticEvent( - eventTypes.select, + 'onSelect', null, nativeEvent, nativeEventTarget, diff --git a/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js b/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js index ccad5ffb15..612d30ea10 100644 --- a/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js @@ -7,10 +7,7 @@ * @flow */ -import type { - TopLevelType, - DOMTopLevelEventType, -} from '../../events/TopLevelEventTypes'; +import type {TopLevelType} from '../../events/TopLevelEventTypes'; import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; import type { AnyNativeEvent, @@ -22,7 +19,7 @@ import SyntheticEvent from '../../events/SyntheticEvent'; import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes'; import { - topLevelEventsToDispatchConfig, + topLevelEventsToReactNames, simpleEventPluginEventTypes, } from '../DOMEventProperties'; import { @@ -46,41 +43,6 @@ import getEventCharCode from '../getEventCharCode'; import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags'; -// Only used in DEV for exhaustiveness validation. -const knownHTMLTopLevelTypes: Array = [ - DOMTopLevelEventTypes.TOP_ABORT, - DOMTopLevelEventTypes.TOP_CANCEL, - DOMTopLevelEventTypes.TOP_CAN_PLAY, - DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, - DOMTopLevelEventTypes.TOP_CLOSE, - DOMTopLevelEventTypes.TOP_DURATION_CHANGE, - DOMTopLevelEventTypes.TOP_EMPTIED, - DOMTopLevelEventTypes.TOP_ENCRYPTED, - DOMTopLevelEventTypes.TOP_ENDED, - DOMTopLevelEventTypes.TOP_ERROR, - DOMTopLevelEventTypes.TOP_INPUT, - DOMTopLevelEventTypes.TOP_INVALID, - DOMTopLevelEventTypes.TOP_LOAD, - DOMTopLevelEventTypes.TOP_LOADED_DATA, - DOMTopLevelEventTypes.TOP_LOADED_METADATA, - DOMTopLevelEventTypes.TOP_LOAD_START, - DOMTopLevelEventTypes.TOP_PAUSE, - DOMTopLevelEventTypes.TOP_PLAY, - DOMTopLevelEventTypes.TOP_PLAYING, - DOMTopLevelEventTypes.TOP_PROGRESS, - DOMTopLevelEventTypes.TOP_RATE_CHANGE, - DOMTopLevelEventTypes.TOP_RESET, - DOMTopLevelEventTypes.TOP_SEEKED, - DOMTopLevelEventTypes.TOP_SEEKING, - DOMTopLevelEventTypes.TOP_STALLED, - DOMTopLevelEventTypes.TOP_SUBMIT, - DOMTopLevelEventTypes.TOP_SUSPEND, - DOMTopLevelEventTypes.TOP_TIME_UPDATE, - DOMTopLevelEventTypes.TOP_TOGGLE, - DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, - DOMTopLevelEventTypes.TOP_WAITING, -]; - function extractEvents( dispatchQueue: DispatchQueue, topLevelType: TopLevelType, @@ -90,8 +52,8 @@ function extractEvents( eventSystemFlags: EventSystemFlags, targetContainer: null | EventTarget, ): void { - const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType); - if (!dispatchConfig) { + const reactName = topLevelEventsToReactNames.get(topLevelType); + if (reactName === undefined) { return; } let EventConstructor; @@ -179,25 +141,12 @@ function extractEvents( EventConstructor = SyntheticPointerEvent; break; default: - if (__DEV__) { - if ( - knownHTMLTopLevelTypes.indexOf(topLevelType) === -1 && - dispatchConfig.customEvent !== true - ) { - console.error( - 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' + - 'is likely caused by a bug in React. Please file an issue.', - topLevelType, - ); - } - } - // HTML Events - // @see http://www.w3.org/TR/html5/index.html#events-0 + // Unknown event. This is used by createEventHandle. EventConstructor = SyntheticEvent; break; } const event = new EventConstructor( - dispatchConfig, + reactName, null, nativeEvent, nativeEventTarget, diff --git a/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js b/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js index 08da87d93e..8069f7cb18 100644 --- a/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js +++ b/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js @@ -43,8 +43,11 @@ if (__DEV__) { // We can't rely on the event system being injected on the server. if (eventRegistry != null) { - const {registrationNames, possibleRegistrationNames} = eventRegistry; - if (registrationNames.hasOwnProperty(name)) { + const { + registrationNameDependencies, + possibleRegistrationNames, + } = eventRegistry; + if (registrationNameDependencies.hasOwnProperty(name)) { return true; } const registrationName = possibleRegistrationNames.hasOwnProperty( diff --git a/packages/react-dom/src/test-utils/ReactTestUtils.js b/packages/react-dom/src/test-utils/ReactTestUtils.js index 88d1b0ea64..02ba37a860 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtils.js +++ b/packages/react-dom/src/test-utils/ReactTestUtils.js @@ -491,14 +491,16 @@ function getListener(inst: Fiber, registrationName: string) { } function listenerAtPhase(inst, event, propagationPhase: PropagationPhases) { - const registrationName = - event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + let registrationName = event._reactName; + if (propagationPhase === 'captured') { + registrationName += 'Capture'; + } return getListener(inst, registrationName); } function accumulateDispatches(inst, ignoredDirection, event) { - if (inst && event && event.dispatchConfig.registrationName) { - const registrationName = event.dispatchConfig.registrationName; + if (inst && event && event._reactName) { + const registrationName = event._reactName; const listener = getListener(inst, registrationName); if (listener) { if (event._dispatchListeners == null) { @@ -533,13 +535,13 @@ function accumulateDirectionalDispatches(inst, phase, event) { } function accumulateDirectDispatchesSingle(event) { - if (event && event.dispatchConfig.registrationName) { + if (event && event._reactName) { accumulateDispatches(event._targetInst, null, event); } } function accumulateTwoPhaseDispatchesSingle(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { + if (event && event._reactName) { traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); } } @@ -577,27 +579,14 @@ function makeSimulator(eventType) { 'a component instance. Pass the DOM node you wish to simulate the event on instead.', ); - // Reconstruct more or less what the original event system produced. - // We could remove this indirection here but we also don't plan to invest in Simulate anyway. - const dispatchConfig = {}; - if (directDispatchEventTypes.has(eventType)) { - dispatchConfig.registrationName = - 'on' + eventType[0].toUpperCase() + eventType.slice(1); - } else { - dispatchConfig.phasedRegistrationNames = { - bubbled: 'on' + eventType[0].toUpperCase() + eventType.slice(1), - captured: - 'on' + eventType[0].toUpperCase() + eventType.slice(1) + 'Capture', - }; - } - + const reactName = 'on' + eventType[0].toUpperCase() + eventType.slice(1); const fakeNativeEvent = new Event(); fakeNativeEvent.target = domNode; fakeNativeEvent.type = eventType.toLowerCase(); const targetInst = getInstanceFromNode(domNode); const event = new SyntheticEvent( - dispatchConfig, + reactName, targetInst, fakeNativeEvent, domNode, @@ -608,10 +597,10 @@ function makeSimulator(eventType) { event.persist(); Object.assign(event, eventData); - if (dispatchConfig.phasedRegistrationNames) { - accumulateTwoPhaseDispatchesSingle(event); - } else { + if (directDispatchEventTypes.has(eventType)) { accumulateDirectDispatchesSingle(event); + } else { + accumulateTwoPhaseDispatchesSingle(event); } ReactDOM.unstable_batchedUpdates(function() {