ModernEventSystem: refactor accumulateTwoPhaseListeners (#18274)

This commit is contained in:
Dominic Gannaway 2020-03-11 18:55:01 +00:00 committed by GitHub
parent 8fe066fdac
commit 30a998debf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 10 deletions

View File

@ -31,4 +31,7 @@ export type ReactSyntheticEvent = {|
nativeEventTarget: EventTarget,
) => ReactSyntheticEvent,
isPersistent: () => boolean,
_dispatchInstances: null | Array<Fiber>,
_dispatchListeners: null | Array<Function>,
_targetInst: null | Fiber,
|};

View File

@ -76,6 +76,8 @@ function SyntheticEvent(
this.dispatchConfig = dispatchConfig;
this._targetInst = targetInst;
this.nativeEvent = nativeEvent;
this._dispatchListeners = null;
this._dispatchInstances = null;
const Interface = this.constructor.Interface;
for (const propName in Interface) {

View File

@ -7,7 +7,6 @@
import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
import {canUseDOM} from 'shared/ExecutionEnvironment';
import {
@ -29,6 +28,7 @@ import {
} from './FallbackCompositionState';
import SyntheticCompositionEvent from './SyntheticCompositionEvent';
import SyntheticInputEvent from './SyntheticInputEvent';
import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
const START_KEYCODE = 229;
@ -276,7 +276,7 @@ function extractCompositionEvent(
}
}
accumulateTwoPhaseDispatchesSingle(event);
accumulateTwoPhaseListeners(event);
return event;
}
@ -437,7 +437,7 @@ function extractBeforeInputEvent(
);
event.data = chars;
accumulateTwoPhaseDispatchesSingle(event);
accumulateTwoPhaseListeners(event);
return event;
}

View File

@ -6,7 +6,6 @@
*/
import {runEventsInBatch} from 'legacy-events/EventBatching';
import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
import {enqueueStateRestore} from 'legacy-events/ReactControlledComponent';
import {batchedUpdates} from 'legacy-events/ReactGenericBatching';
import SyntheticEvent from 'legacy-events/SyntheticEvent';
@ -28,6 +27,8 @@ import isEventSupported from './isEventSupported';
import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
import {updateValueIfChanged} from '../client/inputValueTracking';
import {setDefaultValue} from '../client/ReactDOMInput';
import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
import {disableInputAttributeSyncing} from 'shared/ReactFeatureFlags';
const eventTypes = {
@ -59,7 +60,7 @@ function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
event.type = 'change';
// Flag this event loop as needing state restore.
enqueueStateRestore(target);
accumulateTwoPhaseDispatchesSingle(event);
accumulateTwoPhaseListeners(event);
return event;
}
/**

View File

@ -19,8 +19,9 @@ import {registrationNameDependencies} from 'legacy-events/EventPluginRegistry';
import {batchedEventUpdates} from 'legacy-events/ReactGenericBatching';
import {executeDispatchesInOrder} from 'legacy-events/EventPluginUtils';
import {plugins} from 'legacy-events/EventPluginRegistry';
import getListener from 'legacy-events/getListener';
import {HostRoot, HostPortal} from 'shared/ReactWorkTags';
import {HostRoot, HostPortal, HostComponent} from 'shared/ReactWorkTags';
import {addTrappedEventListener} from './ReactDOMEventListener';
import getEventTarget from './getEventTarget';
@ -305,3 +306,46 @@ export function attachElementListener(listener: ReactDOMListener): void {
export function detachElementListener(listener: ReactDOMListener): void {
// TODO
}
export function accumulateTwoPhaseListeners(event: ReactSyntheticEvent): void {
const phasedRegistrationNames = event.dispatchConfig.phasedRegistrationNames;
if (phasedRegistrationNames == null) {
return;
}
const {bubbled, captured} = phasedRegistrationNames;
const dispatchListeners = [];
const dispatchInstances = [];
let node = event._targetInst;
let hasListeners = false;
// Accumulate all instances and listeners via the target -> root path.
while (node !== null) {
// We only care for listeners that are on HostComponents (i.e. <div>)
if (node.tag === HostComponent) {
// Standard React on* listeners, i.e. onClick prop
const captureListener = getListener(node, captured);
if (captureListener != null) {
hasListeners = true;
// Capture listeners/instances should go at the start, so we
// unshift them to the start of the array.
dispatchListeners.unshift(captureListener);
dispatchInstances.unshift(node);
}
const bubbleListener = getListener(node, bubbled);
if (bubbleListener != null) {
hasListeners = true;
// Bubble listeners/instances should go at the end, so we
// push them to the end of the array.
dispatchListeners.push(bubbleListener);
dispatchInstances.push(node);
}
}
node = node.return;
}
// To prevent allocation to the event unless we actually
// have listeners we use the flag we would have set above.
if (hasListeners) {
event._dispatchListeners = dispatchListeners;
event._dispatchInstances = dispatchInstances;
}
}

View File

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/
import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
import {canUseDOM} from 'shared/ExecutionEnvironment';
import SyntheticEvent from 'legacy-events/SyntheticEvent';
import isTextInputElement from 'shared/isTextInputElement';
@ -27,6 +26,7 @@ import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
import {hasSelectionCapabilities} from '../client/ReactInputSelection';
import {DOCUMENT_NODE} from '../shared/HTMLNodeType';
import {isListeningToAllDependencies} from './DOMEventListenerMap';
import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
const skipSelectionChangeEvent =
canUseDOM && 'documentMode' in document && document.documentMode <= 11;
@ -135,7 +135,7 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
syntheticEvent.type = 'select';
syntheticEvent.target = activeElement;
accumulateTwoPhaseDispatchesSingle(syntheticEvent);
accumulateTwoPhaseListeners(syntheticEvent);
return syntheticEvent;
}

View File

@ -16,7 +16,6 @@ import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {PluginModule} from 'legacy-events/PluginModuleType';
import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
import {accumulateTwoPhaseDispatchesSingle} from 'legacy-events/EventPropagators';
import SyntheticEvent from 'legacy-events/SyntheticEvent';
import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes';
@ -37,6 +36,7 @@ import SyntheticTransitionEvent from './SyntheticTransitionEvent';
import SyntheticUIEvent from './SyntheticUIEvent';
import SyntheticWheelEvent from './SyntheticWheelEvent';
import getEventCharCode from './getEventCharCode';
import {accumulateTwoPhaseListeners} from './DOMModernPluginEventSystem';
// Only used in DEV for exhaustiveness validation.
const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
@ -191,7 +191,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
nativeEvent,
nativeEventTarget,
);
accumulateTwoPhaseDispatchesSingle(event);
accumulateTwoPhaseListeners(event);
return event;
},
};