diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index 5cc6981d82aad..7e20c5452badd 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -59,7 +59,7 @@ import { import {getListenerMapForElement} from '../events/DOMEventListenerMap'; import { addResponderEventSystemEvent, - removeActiveResponderEventSystemEvent, + removePassiveResponderEventSystemEvent, } from '../events/ReactDOMEventListener.js'; import {mediaEventTypes} from '../events/DOMTopLevelEventTypes'; import { @@ -1360,7 +1360,7 @@ export function listenToEventResponderEventTypes( const passiveKey = targetEventType + '_passive'; const passiveListener = listenerMap.get(passiveKey); if (passiveListener != null) { - removeActiveResponderEventSystemEvent( + removePassiveResponderEventSystemEvent( document, targetEventType, passiveListener, diff --git a/packages/react-dom/src/events/ReactDOMEventListener.js b/packages/react-dom/src/events/ReactDOMEventListener.js index 040029c46d7f4..13f40eb95deb7 100644 --- a/packages/react-dom/src/events/ReactDOMEventListener.js +++ b/packages/react-dom/src/events/ReactDOMEventListener.js @@ -105,6 +105,7 @@ export function addResponderEventSystemEvent( } else { eventFlags |= IS_ACTIVE; } + let fbListener; // Check if interactive and wrap in discreteUpdates const listener = dispatchEvent.bind( null, @@ -113,30 +114,34 @@ export function addResponderEventSystemEvent( document, ); if (passiveBrowserEventsSupported) { - addEventCaptureListenerWithPassiveFlag( + fbListener = addEventCaptureListenerWithPassiveFlag( document, topLevelType, listener, passive, ); } else { - addEventCaptureListener(document, topLevelType, listener); + fbListener = addEventCaptureListener(document, topLevelType, listener); } - return listener; + return fbListener || listener; } -export function removeActiveResponderEventSystemEvent( +export function removePassiveResponderEventSystemEvent( document: Document, topLevelType: string, listener: any => void, ) { - if (passiveBrowserEventsSupported) { - document.removeEventListener(topLevelType, listener, { - capture: true, - passive: false, - }); + if (listener.remove) { + listener.remove(); } else { - document.removeEventListener(topLevelType, listener, true); + if (passiveBrowserEventsSupported) { + document.removeEventListener(topLevelType, listener, { + capture: true, + passive: true, + }); + } else { + document.removeEventListener(topLevelType, listener, true); + } } } diff --git a/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js b/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js index c3fa398e83766..62fda3edfb5c1 100644 --- a/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js +++ b/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js @@ -948,4 +948,39 @@ describe('DOMEventResponderSystem', () => { document.body.removeChild(domNode); expect(onEvent).toBeCalled(); }); + + it('event upgrading should work correctly', () => { + let eventResponderFiredCount = 0; + const buttonRef = React.createRef(); + + const TestResponder = createEventResponder({ + targetEventTypes: ['click'], + onEvent: (event, context, props, state) => { + eventResponderFiredCount++; + if (!state.addedRootEventTypes) { + context.addRootEventTypes(['click_active']); + } + state.addedRootEventTypes = true; + }, + }); + + function Test() { + const listener = React.DEPRECATED_useResponder(TestResponder, {}); + + return ( + + ); + } + + ReactDOM.render(, container); + expect(container.innerHTML).toBe(''); + + let buttonElement = buttonRef.current; + dispatchClickEvent(buttonElement); + expect(eventResponderFiredCount).toBe(1); + dispatchClickEvent(buttonElement); + expect(eventResponderFiredCount).toBe(2); + }); });