Skip to content

Commit a3bf668

Browse files
authored
Flare: Fix listener upgrade bug (#18270)
1 parent 526c12f commit a3bf668

File tree

5 files changed

+75
-32
lines changed

5 files changed

+75
-32
lines changed

packages/react-dom/src/client/ReactDOMComponent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ import {
5959
import {getListenerMapForElement} from '../events/DOMEventListenerMap';
6060
import {
6161
addResponderEventSystemEvent,
62-
removeActiveResponderEventSystemEvent,
62+
removeTrappedPassiveEventListener,
6363
} from '../events/ReactDOMEventListener.js';
6464
import {mediaEventTypes} from '../events/DOMTopLevelEventTypes';
6565
import {
@@ -1360,7 +1360,7 @@ export function listenToEventResponderEventTypes(
13601360
const passiveKey = targetEventType + '_passive';
13611361
const passiveListener = listenerMap.get(passiveKey);
13621362
if (passiveListener != null) {
1363-
removeActiveResponderEventSystemEvent(
1363+
removeTrappedPassiveEventListener(
13641364
document,
13651365
targetEventType,
13661366
passiveListener,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {
3939
getRawEventName,
4040
mediaEventTypes,
4141
} from './DOMTopLevelEventTypes';
42-
import {trapEventForPluginEventSystem} from './ReactDOMEventListener';
42+
import {addTrappedEventListener} from './ReactDOMEventListener';
4343

4444
/**
4545
* Summary of `DOMEventPluginSystem` event handling:
@@ -368,12 +368,12 @@ export function legacyTrapBubbledEvent(
368368
topLevelType: DOMTopLevelEventType,
369369
element: Document | Element,
370370
): void {
371-
trapEventForPluginEventSystem(element, topLevelType, false);
371+
addTrappedEventListener(element, topLevelType, false);
372372
}
373373

374374
export function legacyTrapCapturedEvent(
375375
topLevelType: DOMTopLevelEventType,
376376
element: Document | Element,
377377
): void {
378-
trapEventForPluginEventSystem(element, topLevelType, true);
378+
addTrappedEventListener(element, topLevelType, true);
379379
}

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {plugins} from 'legacy-events/EventPluginRegistry';
2121

2222
import {HostRoot, HostPortal} from 'shared/ReactWorkTags';
2323

24-
import {trapEventForPluginEventSystem} from './ReactDOMEventListener';
24+
import {addTrappedEventListener} from './ReactDOMEventListener';
2525
import getEventTarget from './getEventTarget';
2626
import {getListenerMapForElement} from './DOMEventListenerMap';
2727
import {
@@ -149,11 +149,7 @@ export function listenToTopLevelEvent(
149149
): void {
150150
if (!listenerMap.has(topLevelType)) {
151151
const isCapturePhase = capturePhaseEvents.has(topLevelType);
152-
trapEventForPluginEventSystem(
153-
rootContainerElement,
154-
topLevelType,
155-
isCapturePhase,
156-
);
152+
addTrappedEventListener(rootContainerElement, topLevelType, isCapturePhase);
157153
listenerMap.set(topLevelType, null);
158154
}
159155
}
@@ -196,7 +192,7 @@ function willDeferLaterForFBLegacyPrimer(nativeEvent: any): boolean {
196192
if (node.tagName === 'A' && validFBLegacyPrimerRels.has(node.rel)) {
197193
const legacyFBSupport = true;
198194
const isCapture = nativeEvent.eventPhase === 1;
199-
trapEventForPluginEventSystem(
195+
addTrappedEventListener(
200196
document,
201197
((type: any): DOMTopLevelEventType),
202198
isCapture,

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

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export function addResponderEventSystemEvent(
105105
} else {
106106
eventFlags |= IS_ACTIVE;
107107
}
108+
let fbListener;
108109
// Check if interactive and wrap in discreteUpdates
109110
const listener = dispatchEvent.bind(
110111
null,
@@ -113,39 +114,27 @@ export function addResponderEventSystemEvent(
113114
document,
114115
);
115116
if (passiveBrowserEventsSupported) {
116-
addEventCaptureListenerWithPassiveFlag(
117+
fbListener = addEventCaptureListenerWithPassiveFlag(
117118
document,
118119
topLevelType,
119120
listener,
120121
passive,
121122
);
122123
} else {
123-
addEventCaptureListener(document, topLevelType, listener);
124-
}
125-
return listener;
126-
}
127-
128-
export function removeActiveResponderEventSystemEvent(
129-
document: Document,
130-
topLevelType: string,
131-
listener: any => void,
132-
) {
133-
if (passiveBrowserEventsSupported) {
134-
document.removeEventListener(topLevelType, listener, {
135-
capture: true,
136-
passive: false,
137-
});
138-
} else {
139-
document.removeEventListener(topLevelType, listener, true);
124+
fbListener = addEventCaptureListener(document, topLevelType, listener);
140125
}
126+
// If we have an fbListener, then use that.
127+
// We'll only have one if we use the forked
128+
// EventListener-www module in FB builds.
129+
return fbListener || listener;
141130
}
142131

143-
export function trapEventForPluginEventSystem(
132+
export function addTrappedEventListener(
144133
container: Document | Element,
145134
topLevelType: DOMTopLevelEventType,
146135
capture: boolean,
147136
legacyFBSupport?: boolean,
148-
): void {
137+
): any => void {
149138
let listener;
150139
let listenerWrapper;
151140
switch (getEventPriorityForPluginSystem(topLevelType)) {
@@ -203,6 +192,29 @@ export function trapEventForPluginEventSystem(
203192
} else {
204193
fbListener = addEventBubbleListener(container, rawEventName, listener);
205194
}
195+
// If we have an fbListener, then use that.
196+
// We'll only have one if we use the forked
197+
// EventListener-www module in FB builds.
198+
return fbListener || listener;
199+
}
200+
201+
export function removeTrappedPassiveEventListener(
202+
document: Document,
203+
topLevelType: string,
204+
listener: any => void,
205+
) {
206+
if (listener.remove != null) {
207+
listener.remove();
208+
} else {
209+
if (passiveBrowserEventsSupported) {
210+
document.removeEventListener(topLevelType, listener, {
211+
capture: true,
212+
passive: true,
213+
});
214+
} else {
215+
document.removeEventListener(topLevelType, listener, true);
216+
}
217+
}
206218
}
207219

208220
function dispatchDiscreteEvent(

packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,4 +948,39 @@ describe('DOMEventResponderSystem', () => {
948948
document.body.removeChild(domNode);
949949
expect(onEvent).toBeCalled();
950950
});
951+
952+
it('event upgrading should work correctly', () => {
953+
let eventResponderFiredCount = 0;
954+
const buttonRef = React.createRef();
955+
956+
const TestResponder = createEventResponder({
957+
targetEventTypes: ['click'],
958+
onEvent: (event, context, props, state) => {
959+
eventResponderFiredCount++;
960+
if (!state.addedRootEventTypes) {
961+
context.addRootEventTypes(['click_active']);
962+
}
963+
state.addedRootEventTypes = true;
964+
},
965+
});
966+
967+
function Test() {
968+
const listener = React.DEPRECATED_useResponder(TestResponder, {});
969+
970+
return (
971+
<button ref={buttonRef} DEPRECATED_flareListeners={listener}>
972+
Click me!
973+
</button>
974+
);
975+
}
976+
977+
ReactDOM.render(<Test />, container);
978+
expect(container.innerHTML).toBe('<button>Click me!</button>');
979+
980+
let buttonElement = buttonRef.current;
981+
dispatchClickEvent(buttonElement);
982+
expect(eventResponderFiredCount).toBe(1);
983+
dispatchClickEvent(buttonElement);
984+
expect(eventResponderFiredCount).toBe(2);
985+
});
951986
});

0 commit comments

Comments
 (0)