@@ -13,6 +13,7 @@ import type {ReactNodeList} from 'shared/ReactTypes';
13
13
// TODO: This type is shared between the reconciler and ReactDOM, but will
14
14
// eventually be lifted out to the renderer.
15
15
import type { FiberRoot } from 'react-reconciler/src/ReactFiberRoot' ;
16
+ import { findHostInstanceWithNoPortals } from 'react-reconciler/inline.dom' ;
16
17
17
18
export type RootType = {
18
19
render ( children : ReactNodeList ) : void ,
@@ -63,15 +64,30 @@ function ReactDOMBlockingRoot(
63
64
ReactDOMRoot . prototype . render = ReactDOMBlockingRoot . prototype . render = function (
64
65
children : ReactNodeList ,
65
66
) : void {
67
+ const root = this . _internalRoot ;
66
68
if ( __DEV__ ) {
67
69
if ( typeof arguments [ 1 ] === 'function' ) {
68
70
console . error (
69
71
'render(...): does not support the second callback argument. ' +
70
72
'To execute a side effect after rendering, declare it in a component body with useEffect().' ,
71
73
) ;
72
74
}
75
+ const container = root . containerInfo ;
76
+
77
+ if ( container . nodeType !== COMMENT_NODE ) {
78
+ const hostInstance = findHostInstanceWithNoPortals ( root . current ) ;
79
+ if ( hostInstance ) {
80
+ if ( hostInstance . parentNode !== container ) {
81
+ console . error (
82
+ 'render(...): It looks like the React-rendered content of the ' +
83
+ 'root container was removed without using React. This is not ' +
84
+ 'supported and will cause errors. Instead, call ' +
85
+ "root.unmount() to empty a root's container." ,
86
+ ) ;
87
+ }
88
+ }
89
+ }
73
90
}
74
- const root = this . _internalRoot ;
75
91
updateContainer ( children , root , null , null ) ;
76
92
} ;
77
93
@@ -96,6 +112,21 @@ function createRootImpl(
96
112
tag : RootTag ,
97
113
options : void | RootOptions ,
98
114
) {
115
+ if ( __DEV__ ) {
116
+ if (
117
+ container . nodeType === ELEMENT_NODE &&
118
+ ( ( container : any ) : Element ) . tagName &&
119
+ ( ( container : any ) : Element ) . tagName . toUpperCase ( ) === 'BODY'
120
+ ) {
121
+ console . error (
122
+ 'createRoot(): Creating roots directly with document.body is ' +
123
+ 'discouraged, since its children are often manipulated by third-party ' +
124
+ 'scripts and browser extensions. This may lead to subtle ' +
125
+ 'reconciliation issues. Try using a container element created ' +
126
+ 'for your app.' ,
127
+ ) ;
128
+ }
129
+ }
99
130
// Tag is either LegacyRoot or Concurrent Root
100
131
const hydrate = options != null && options . hydrate === true ;
101
132
const hydrationCallbacks =
0 commit comments