diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index 97bfa60274..14e80522b1 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -190,6 +190,11 @@ export function getChildHostContextForEvent( let eventData = null; if (type === REACT_EVENT_COMPONENT_TYPE) { + warning( + parentHostContextDev.eventData === null || + !parentHostContextDev.eventData.isEventTarget, + 'validateDOMNesting: React event targets must not have event components as children.', + ); eventData = { isEventComponent: true, isEventTarget: false, diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 1d7fa86fbc..585406898e 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -268,6 +268,10 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { ) { if (__DEV__ && enableEventAPI) { if (type === REACT_EVENT_COMPONENT_TYPE) { + warning( + parentHostContext !== EVENT_TARGET_CONTEXT, + 'validateDOMNesting: React event targets must not have event components as children.', + ); return EVENT_COMPONENT_CONTEXT; } else if (type === REACT_EVENT_TARGET_TYPE) { warning( diff --git a/packages/react-reconciler/src/__tests__/ReactFiberEvents-test-internal.js b/packages/react-reconciler/src/__tests__/ReactFiberEvents-test-internal.js index 40911388c7..3cfed203ad 100644 --- a/packages/react-reconciler/src/__tests__/ReactFiberEvents-test-internal.js +++ b/packages/react-reconciler/src/__tests__/ReactFiberEvents-test-internal.js @@ -200,6 +200,25 @@ describe('ReactFiberEvents', () => { 'Warning: validateDOMNesting: React event targets must be direct children of event components.', ); }); + + it('should warn if an event target has an event component as a child', () => { + const Test = () => ( + + + + Child 1 + + + + ); + + expect(() => { + ReactNoop.render(); + expect(Scheduler).toFlushWithoutYielding(); + }).toWarnDev( + 'Warning: validateDOMNesting: React event targets must not have event components as children.', + ); + }); }); describe('TestRenderer', () => { @@ -368,6 +387,26 @@ describe('ReactFiberEvents', () => { 'Warning: validateDOMNesting: React event targets must be direct children of event components.', ); }); + + it('should warn if an event target has an event component as a child', () => { + const Test = () => ( + + + + Child 1 + + + + ); + + const root = ReactTestRenderer.create(null); + expect(() => { + root.update(); + expect(Scheduler).toFlushWithoutYielding(); + }).toWarnDev( + 'Warning: validateDOMNesting: React event targets must not have event components as children.', + ); + }); }); describe('ReactDOM', () => { @@ -535,6 +574,26 @@ describe('ReactFiberEvents', () => { 'Warning: validateDOMNesting: React event targets must be direct children of event components.', ); }); + + it('should warn if an event target has an event component as a child', () => { + const Test = () => ( + + + + Child 1 + + + + ); + + expect(() => { + const container = document.createElement('div'); + ReactDOM.render(, container); + expect(Scheduler).toFlushWithoutYielding(); + }).toWarnDev( + 'Warning: validateDOMNesting: React event targets must not have event components as children.', + ); + }); }); describe('ReactDOMServer', () => { diff --git a/packages/react-test-renderer/src/ReactTestHostConfig.js b/packages/react-test-renderer/src/ReactTestHostConfig.js index a86fc4b266..a5ac30273b 100644 --- a/packages/react-test-renderer/src/ReactTestHostConfig.js +++ b/packages/react-test-renderer/src/ReactTestHostConfig.js @@ -133,6 +133,10 @@ export function getChildHostContextForEvent( ): HostContext { if (__DEV__ && enableEventAPI) { if (type === REACT_EVENT_COMPONENT_TYPE) { + warning( + parentHostContext !== EVENT_TARGET_CONTEXT, + 'validateDOMNesting: React event targets must not have event components as children.', + ); return EVENT_COMPONENT_CONTEXT; } else if (type === REACT_EVENT_TARGET_TYPE) { warning(