Skip to content

Commit

Permalink
ReactDOM.useEvent: wire to event system to the hook (#18304)
Browse files Browse the repository at this point in the history
  • Loading branch information
trueadm authored Mar 16, 2020
1 parent 297f758 commit c804f9a
Show file tree
Hide file tree
Showing 12 changed files with 710 additions and 6 deletions.
10 changes: 9 additions & 1 deletion packages/legacy-events/EventPluginUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,20 @@ export function executeDispatchesInOrder(event) {
validateEventDispatches(event);
}
if (Array.isArray(dispatchListeners)) {
let previousInstance;
for (let i = 0; i < dispatchListeners.length; i++) {
if (event.isPropagationStopped()) {
const instance = dispatchInstances[i];
// We check if the instance was the same as the last one,
// if it was, then we're still on the same instance thus
// propagation should not stop. If we add support for
// stopImmediatePropagation at some point, then we'll
// need to handle that case here differently.
if (instance !== previousInstance && event.isPropagationStopped()) {
break;
}
// Listeners and Instances are two parallel arrays that are always in sync.
executeDispatch(event, dispatchListeners[i], dispatchInstances[i]);
previousInstance = instance;
}
} else if (dispatchListeners) {
executeDispatch(event, dispatchListeners, dispatchInstances);
Expand Down
4 changes: 4 additions & 0 deletions packages/react-art/src/ReactARTHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,10 @@ export function beforeRemoveInstance(instance) {
// noop
}

export function registerEvent(event: any, rootContainerInstance: any) {
throw new Error('Not yet implemented.');
}

export function mountEventListener(listener: any) {
throw new Error('Not yet implemented.');
}
Expand Down
37 changes: 37 additions & 0 deletions packages/react-dom/src/client/ReactDOMHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
* @flow
*/

import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
import type {RootType} from './ReactDOMRoot';

import {
precacheFiberNode,
updateFiberProps,
getClosestInstanceFromNode,
getListenersFromTarget,
} from './ReactDOMComponentTree';
import {
createElement,
Expand Down Expand Up @@ -78,7 +80,9 @@ import {
detachElementListener,
isDOMDocument,
isDOMElement,
listenToTopLevelEvent,
} from '../events/DOMModernPluginEventSystem';
import {getListenerMapForElement} from '../events/DOMEventListenerMap';

export type ReactListenerEvent = ReactDOMListenerEvent;
export type ReactListenerMap = ReactDOMListenerMap;
Expand Down Expand Up @@ -529,6 +533,22 @@ export function beforeRemoveInstance(
) {
dispatchBeforeDetachedBlur(((instance: any): HTMLElement));
}
if (enableUseEventAPI) {
// It's unfortunate that we have to do this cleanup, but
// it's necessary otherwise we will leak the host instances
// from the useEvent hook instances Map. We call destroy
// on each listener to ensure we properly remove the instance
// from the instances Map. Note: we have this Map so that we
// can properly unmount instances when the function component
// that the hook is attached to gets unmounted.
const listenersSet = getListenersFromTarget(instance);
if (listenersSet !== null) {
const listeners = Array.from(listenersSet);
for (let i = 0; i < listeners.length; i++) {
listeners[i].destroy(instance);
}
}
}
}

export function removeChild(
Expand Down Expand Up @@ -1083,6 +1103,23 @@ export function getInstanceFromNode(node: HTMLElement): null | Object {
return getClosestInstanceFromNode(node) || null;
}

export function registerEvent(
event: ReactDOMListenerEvent,
rootContainerInstance: Container,
): void {
const {passive, priority, type} = event;
const listenerMap = getListenerMapForElement(rootContainerInstance);
// Add the event listener to the target container (falling back to
// the target if we didn't find one).
listenToTopLevelEvent(
((type: any): DOMTopLevelEventType),
rootContainerInstance,
listenerMap,
passive,
priority,
);
}

export function mountEventListener(listener: ReactDOMListener): void {
if (enableUseEventAPI) {
const {target} = listener;
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dom/src/events/SimpleEventPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
nativeEvent,
nativeEventTarget,
);
accumulateTwoPhaseListeners(event);
accumulateTwoPhaseListeners(event, true);
return event;
},
};
Expand Down
Loading

0 comments on commit c804f9a

Please sign in to comment.