@samitouri / QOS-React / commits / 147179ae82

Fix createEventHandle bug with comment containers (#19348)

Dominic Gannaway committed Jul 14, 2020 at 13:09 UTC 147179ae82039f38fa1a9a72402f578af8fb3ea3
2 files changed +81 -2
packages/react-dom/src/client/ReactDOMEventHandle.js
+5 -2
@@ -22,7 +22,7 @@ import {
22 getEventListenerMap,
23 getFiberFromScopeInstance,
24 } from './ReactDOMComponentTree';
25 -import {ELEMENT_NODE} from '../shared/HTMLNodeType';
25 +import {ELEMENT_NODE, COMMENT_NODE} from '../shared/HTMLNodeType';
26 import {
27 listenToNativeEvent,
28 addEventTypeToDispatchConfig,
@@ -90,7 +90,7 @@ function registerEventOnNearestTargetContainer(
90 ): void {
91 // If it is, find the nearest root or portal and make it
92 // our event handle target container.
93 - const targetContainer = getNearestRootOrPortalContainer(targetFiber);
93 + let targetContainer = getNearestRootOrPortalContainer(targetFiber);
94 if (targetContainer === null) {
95 invariant(
96 false,
@@ -98,6 +98,9 @@ function registerEventOnNearestTargetContainer(
98 'that did not have a corresponding root. This is likely a bug in React.',
99 );
100 }
101 + if (targetContainer.nodeType === COMMENT_NODE) {
102 + targetContainer = ((targetContainer.parentNode: any): Element);
103 + }
104 const listenerMap = getEventListenerMap(targetContainer);
105 listenToNativeEvent(
106 topLevelType,
packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js
+76
@@ -3009,6 +3009,82 @@ describe('DOMModernPluginEventSystem', () => {
3009
3010 expect(onClick).toHaveBeenCalledTimes(1);
3011 });
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 + });
3088 });
3089 });
3090 },