Skip to content

Commit 147179a

Browse files
authored
Fix createEventHandle bug with comment containers (facebook#19348)
1 parent 6d7555b commit 147179a

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
getEventListenerMap,
2323
getFiberFromScopeInstance,
2424
} from './ReactDOMComponentTree';
25-
import {ELEMENT_NODE} from '../shared/HTMLNodeType';
25+
import {ELEMENT_NODE, COMMENT_NODE} from '../shared/HTMLNodeType';
2626
import {
2727
listenToNativeEvent,
2828
addEventTypeToDispatchConfig,
@@ -90,14 +90,17 @@ function registerEventOnNearestTargetContainer(
9090
): void {
9191
// If it is, find the nearest root or portal and make it
9292
// our event handle target container.
93-
const targetContainer = getNearestRootOrPortalContainer(targetFiber);
93+
let targetContainer = getNearestRootOrPortalContainer(targetFiber);
9494
if (targetContainer === null) {
9595
invariant(
9696
false,
9797
'ReactDOM.createEventHandle: setListener called on an target ' +
9898
'that did not have a corresponding root. This is likely a bug in React.',
9999
);
100100
}
101+
if (targetContainer.nodeType === COMMENT_NODE) {
102+
targetContainer = ((targetContainer.parentNode: any): Element);
103+
}
101104
const listenerMap = getEventListenerMap(targetContainer);
102105
listenToNativeEvent(
103106
topLevelType,

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

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,6 +3009,82 @@ describe('DOMModernPluginEventSystem', () => {
30093009

30103010
expect(onClick).toHaveBeenCalledTimes(1);
30113011
});
3012+
3013+
// @gate experimental
3014+
it('handle propagation of click events between disjointed comment roots', () => {
3015+
const buttonRef = React.createRef();
3016+
const divRef = React.createRef();
3017+
const log = [];
3018+
const setClick = ReactDOM.unstable_createEventHandle('click');
3019+
const setClickCapture = ReactDOM.unstable_createEventHandle(
3020+
'click',
3021+
{capture: true},
3022+
);
3023+
const onClick = jest.fn(e =>
3024+
log.push(['bubble', e.currentTarget]),
3025+
);
3026+
const onClickCapture = jest.fn(e =>
3027+
log.push(['capture', e.currentTarget]),
3028+
);
3029+
3030+
function Child() {
3031+
React.useEffect(() => {
3032+
const click1 = setClick(divRef.current, onClick);
3033+
const click2 = setClickCapture(
3034+
divRef.current,
3035+
onClickCapture,
3036+
);
3037+
return () => {
3038+
click1();
3039+
click2();
3040+
};
3041+
});
3042+
3043+
return <div ref={divRef}>Click me!</div>;
3044+
}
3045+
3046+
function Parent() {
3047+
React.useEffect(() => {
3048+
const click1 = setClick(buttonRef.current, onClick);
3049+
const click2 = setClickCapture(
3050+
buttonRef.current,
3051+
onClickCapture,
3052+
);
3053+
return () => {
3054+
click1();
3055+
click2();
3056+
};
3057+
});
3058+
3059+
return <button ref={buttonRef} />;
3060+
}
3061+
3062+
// We use a comment node here, then mount to it
3063+
const disjointedNode = document.createComment(
3064+
' react-mount-point-unstable ',
3065+
);
3066+
ReactDOM.render(<Parent />, container);
3067+
Scheduler.unstable_flushAll();
3068+
buttonRef.current.appendChild(disjointedNode);
3069+
ReactDOM.render(<Child />, disjointedNode);
3070+
Scheduler.unstable_flushAll();
3071+
3072+
const buttonElement = buttonRef.current;
3073+
dispatchClickEvent(buttonElement);
3074+
expect(onClick).toHaveBeenCalledTimes(1);
3075+
expect(onClickCapture).toHaveBeenCalledTimes(1);
3076+
expect(log[0]).toEqual(['capture', buttonElement]);
3077+
expect(log[1]).toEqual(['bubble', buttonElement]);
3078+
3079+
const divElement = divRef.current;
3080+
dispatchClickEvent(divElement);
3081+
expect(onClick).toHaveBeenCalledTimes(3);
3082+
expect(onClickCapture).toHaveBeenCalledTimes(3);
3083+
expect(log[2]).toEqual(['capture', buttonElement]);
3084+
expect(log[3]).toEqual(['capture', divElement]);
3085+
expect(log[4]).toEqual(['bubble', divElement]);
3086+
expect(log[5]).toEqual(['bubble', buttonElement]);
3087+
});
30123088
});
30133089
});
30143090
},

0 commit comments

Comments
 (0)