@@ -43,6 +43,7 @@ import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
4343import getComponentNameFromType from 'shared/getComponentNameFromType' ;
4444import ReactSharedInternals from 'shared/ReactSharedInternals' ;
4545import { has as hasInstance } from 'shared/ReactInstanceMap' ;
46+ import { disableLegacyReactDOMRenderAPIs } from 'shared/ReactFeatureFlags' ;
4647
4748const ReactCurrentOwner = ReactSharedInternals . ReactCurrentOwner ;
4849
@@ -265,78 +266,92 @@ export function hydrate(
265266 container : Container ,
266267 callback : ?Function ,
267268) : React$Component < any , any > | PublicInstance | null {
268- if ( __DEV__ ) {
269- console . error (
270- 'ReactDOM.hydrate is no longer supported in React 18. Use hydrateRoot ' +
271- 'instead. Until you switch to the new API, your app will behave as ' +
272- "if it's running React 17. Learn " +
273- 'more: https://reactjs.org/link/switch-to-createroot' ,
269+ if ( disableLegacyReactDOMRenderAPIs ) {
270+ throw new Error (
271+ 'ReactDOM.hydrate is no longer supported. Use hydrateRoot ' +
272+ 'instead. Learn more: https://reactjs.org/link/switch-to-createroot' ,
274273 ) ;
275- }
276-
277- if ( ! isValidContainerLegacy ( container ) ) {
278- throw new Error ( 'Target container is not a DOM element.' ) ;
279- }
280-
281- if ( __DEV__ ) {
282- const isModernRoot =
283- isContainerMarkedAsRoot ( container ) &&
284- container . _reactRootContainer === undefined ;
285- if ( isModernRoot ) {
274+ } else {
275+ if ( __DEV__ ) {
286276 console . error (
287- 'You are calling ReactDOM.hydrate() on a container that was previously ' +
288- 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
289- 'Did you mean to call hydrateRoot(container, element)?' ,
277+ 'ReactDOM.hydrate is no longer supported in React 18. Use hydrateRoot ' +
278+ 'instead. Until you switch to the new API, your app will behave as ' +
279+ "if it's running React 17. Learn " +
280+ 'more: https://reactjs.org/link/switch-to-createroot' ,
290281 ) ;
291282 }
283+
284+ if ( ! isValidContainerLegacy ( container ) ) {
285+ throw new Error ( 'Target container is not a DOM element.' ) ;
286+ }
287+
288+ if ( __DEV__ ) {
289+ const isModernRoot =
290+ isContainerMarkedAsRoot ( container ) &&
291+ container . _reactRootContainer === undefined ;
292+ if ( isModernRoot ) {
293+ console . error (
294+ 'You are calling ReactDOM.hydrate() on a container that was previously ' +
295+ 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
296+ 'Did you mean to call hydrateRoot(container, element)?' ,
297+ ) ;
298+ }
299+ }
300+ // TODO: throw or warn if we couldn't hydrate?
301+ return legacyRenderSubtreeIntoContainer (
302+ null ,
303+ element ,
304+ container ,
305+ true ,
306+ callback ,
307+ ) ;
292308 }
293- // TODO: throw or warn if we couldn't hydrate?
294- return legacyRenderSubtreeIntoContainer (
295- null ,
296- element ,
297- container ,
298- true ,
299- callback ,
300- ) ;
301309}
302310
303311export function render (
304312 element : React$Element < any > ,
305313 container : Container ,
306314 callback : ?Function ,
307315) : React$Component < any , any > | PublicInstance | null {
308- if ( __DEV__ ) {
309- console . error (
310- 'ReactDOM.render is no longer supported in React 18. Use createRoot ' +
311- 'instead. Until you switch to the new API, your app will behave as ' +
312- "if it's running React 17. Learn " +
313- 'more: https://reactjs.org/link/switch-to-createroot' ,
316+ if ( disableLegacyReactDOMRenderAPIs ) {
317+ throw new Error (
318+ 'ReactDOM.render is no longer supported. Use hydrateRoot instead. ' +
319+ 'Learn more: https://reactjs.org/link/switch-to-createroot' ,
314320 ) ;
315- }
316-
317- if ( ! isValidContainerLegacy ( container ) ) {
318- throw new Error ( 'Target container is not a DOM element.' ) ;
319- }
320-
321- if ( __DEV__ ) {
322- const isModernRoot =
323- isContainerMarkedAsRoot ( container ) &&
324- container . _reactRootContainer === undefined ;
325- if ( isModernRoot ) {
321+ } else {
322+ if ( __DEV__ ) {
326323 console . error (
327- 'You are calling ReactDOM.render() on a container that was previously ' +
328- 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
329- 'Did you mean to call root.render(element)?' ,
324+ 'ReactDOM.render is no longer supported in React 18. Use createRoot ' +
325+ 'instead. Until you switch to the new API, your app will behave as ' +
326+ "if it's running React 17. Learn " +
327+ 'more: https://reactjs.org/link/switch-to-createroot' ,
330328 ) ;
331329 }
330+
331+ if ( ! isValidContainerLegacy ( container ) ) {
332+ throw new Error ( 'Target container is not a DOM element.' ) ;
333+ }
334+
335+ if ( __DEV__ ) {
336+ const isModernRoot =
337+ isContainerMarkedAsRoot ( container ) &&
338+ container . _reactRootContainer === undefined ;
339+ if ( isModernRoot ) {
340+ console . error (
341+ 'You are calling ReactDOM.render() on a container that was previously ' +
342+ 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
343+ 'Did you mean to call root.render(element)?' ,
344+ ) ;
345+ }
346+ }
347+ return legacyRenderSubtreeIntoContainer (
348+ null ,
349+ element ,
350+ container ,
351+ false ,
352+ callback ,
353+ ) ;
332354 }
333- return legacyRenderSubtreeIntoContainer (
334- null ,
335- element ,
336- container ,
337- false ,
338- callback ,
339- ) ;
340355}
341356
342357export function unstable_renderSubtreeIntoContainer (
@@ -345,100 +360,116 @@ export function unstable_renderSubtreeIntoContainer(
345360 containerNode : Container ,
346361 callback : ?Function ,
347362) : React$Component < any , any > | PublicInstance | null {
348- if ( __DEV__ ) {
349- console . error (
350- 'ReactDOM.unstable_renderSubtreeIntoContainer() is no longer supported ' +
351- 'in React 18. Consider using a portal instead. Until you switch to ' +
352- "the createRoot API, your app will behave as if it's running React " +
353- '17. Learn more: https://reactjs.org/link/switch-to-createroot' ,
363+ if ( disableLegacyReactDOMRenderAPIs ) {
364+ throw new Error (
365+ 'ReactDOM.unstable_renderSubtreeIntoContainer is no longer supported. ' +
366+ 'Use a portal instead. Learn more: ' +
367+ 'https://reactjs.org/link/switch-to-createroot' ,
354368 ) ;
355- }
369+ } else {
370+ if ( __DEV__ ) {
371+ console . error (
372+ 'ReactDOM.unstable_renderSubtreeIntoContainer() is no longer supported ' +
373+ 'in React 18. Consider using a portal instead. Until you switch to ' +
374+ "the createRoot API, your app will behave as if it's running React " +
375+ '17. Learn more: https://reactjs.org/link/switch-to-createroot' ,
376+ ) ;
377+ }
356378
357- if ( ! isValidContainerLegacy ( containerNode ) ) {
358- throw new Error ( 'Target container is not a DOM element.' ) ;
359- }
379+ if ( ! isValidContainerLegacy ( containerNode ) ) {
380+ throw new Error ( 'Target container is not a DOM element.' ) ;
381+ }
360382
361- if ( parentComponent == null || ! hasInstance ( parentComponent ) ) {
362- throw new Error ( 'parentComponent must be a valid React Component' ) ;
363- }
383+ if ( parentComponent == null || ! hasInstance ( parentComponent ) ) {
384+ throw new Error ( 'parentComponent must be a valid React Component' ) ;
385+ }
364386
365- return legacyRenderSubtreeIntoContainer (
366- parentComponent ,
367- element ,
368- containerNode ,
369- false ,
370- callback ,
371- ) ;
387+ return legacyRenderSubtreeIntoContainer (
388+ parentComponent ,
389+ element ,
390+ containerNode ,
391+ false ,
392+ callback ,
393+ ) ;
394+ }
372395}
373396
374397export function unmountComponentAtNode ( container : Container ) : boolean {
375- if ( ! isValidContainerLegacy ( container ) ) {
398+ if ( disableLegacyReactDOMRenderAPIs ) {
376399 throw new Error (
377- 'unmountComponentAtNode(...): Target container is not a DOM element.' ,
400+ 'ReactDOM.unmountComponentAtNode is no longer supported. Did you mean ' +
401+ 'to call root.unmount()? Learn more: ' +
402+ 'https://reactjs.org/link/switch-to-createroot' ,
378403 ) ;
379- }
380-
381- if ( __DEV__ ) {
382- const isModernRoot =
383- isContainerMarkedAsRoot ( container ) &&
384- container . _reactRootContainer === undefined ;
385- if ( isModernRoot ) {
386- console . error (
387- 'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
388- 'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?' ,
404+ } else {
405+ if ( ! isValidContainerLegacy ( container ) ) {
406+ throw new Error (
407+ 'unmountComponentAtNode(...): Target container is not a DOM element.' ,
389408 ) ;
390409 }
391- }
392410
393- if ( container . _reactRootContainer ) {
394411 if ( __DEV__ ) {
395- const rootEl = getReactRootElementInContainer ( container ) ;
396- const renderedByDifferentReact = rootEl && ! getInstanceFromNode ( rootEl ) ;
397- if ( renderedByDifferentReact ) {
412+ const isModernRoot =
413+ isContainerMarkedAsRoot ( container ) &&
414+ container . _reactRootContainer === undefined ;
415+ if ( isModernRoot ) {
398416 console . error (
399- " unmountComponentAtNode(): The node you're attempting to unmount " +
400- 'was rendered by another copy of React. ' ,
417+ 'You are calling ReactDOM. unmountComponentAtNode() on a container that was previously ' +
418+ 'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()? ' ,
401419 ) ;
402420 }
403421 }
404422
405- // Unmount should not be batched.
406- flushSync ( ( ) => {
407- legacyRenderSubtreeIntoContainer ( null , null , container , false , ( ) => {
408- // $FlowFixMe[incompatible-type] This should probably use `delete container._reactRootContainer`
409- container . _reactRootContainer = null ;
410- unmarkContainerAsRoot ( container ) ;
423+ if ( container . _reactRootContainer ) {
424+ if ( __DEV__ ) {
425+ const rootEl = getReactRootElementInContainer ( container ) ;
426+ const renderedByDifferentReact = rootEl && ! getInstanceFromNode ( rootEl ) ;
427+ if ( renderedByDifferentReact ) {
428+ console . error (
429+ "unmountComponentAtNode(): The node you're attempting to unmount " +
430+ 'was rendered by another copy of React.' ,
431+ ) ;
432+ }
433+ }
434+
435+ // Unmount should not be batched.
436+ flushSync ( ( ) => {
437+ legacyRenderSubtreeIntoContainer ( null , null , container , false , ( ) => {
438+ // $FlowFixMe[incompatible-type] This should probably use `delete container._reactRootContainer`
439+ container . _reactRootContainer = null ;
440+ unmarkContainerAsRoot ( container ) ;
441+ } ) ;
411442 } ) ;
412- } ) ;
413- // If you call unmountComponentAtNode twice in quick succession, you'll
414- // get `true` twice. That's probably fine?
415- return true ;
416- } else {
417- if ( __DEV__ ) {
418- const rootEl = getReactRootElementInContainer ( container ) ;
419- const hasNonRootReactChild = ! ! ( rootEl && getInstanceFromNode ( rootEl ) ) ;
420-
421- // Check if the container itself is a React root node.
422- const isContainerReactRoot =
423- container . nodeType === ELEMENT_NODE &&
424- isValidContainerLegacy ( container . parentNode ) &&
425- // $FlowFixMe[prop-missing ]
426- // $FlowFixMe[incompatible-use]
427- ! ! container . parentNode . _reactRootContainer ;
428-
429- if ( hasNonRootReactChild ) {
430- console . error (
431- "unmountComponentAtNode(): The node you're attempting to unmount " +
432- 'was rendered by React and is not a top-level container. %s' ,
433- isContainerReactRoot
434- ? 'You may have accidentally passed in a React root node instead ' +
435- 'of its container.'
436- : 'Instead, have the parent component update its state and ' +
437- 'rerender in order to remove this component.' ,
438- ) ;
443+ // If you call unmountComponentAtNode twice in quick succession, you'll
444+ // get `true` twice. That's probably fine?
445+ return true ;
446+ } else {
447+ if ( __DEV__ ) {
448+ const rootEl = getReactRootElementInContainer ( container ) ;
449+ const hasNonRootReactChild = ! ! ( rootEl && getInstanceFromNode ( rootEl ) ) ;
450+
451+ // Check if the container itself is a React root node.
452+ const isContainerReactRoot =
453+ container . nodeType === ELEMENT_NODE &&
454+ isValidContainerLegacy ( container . parentNode ) &&
455+ // $FlowFixMe[prop-missing]
456+ // $FlowFixMe[incompatible-use ]
457+ ! ! container . parentNode . _reactRootContainer ;
458+
459+ if ( hasNonRootReactChild ) {
460+ console . error (
461+ "unmountComponentAtNode(): The node you're attempting to unmount " +
462+ 'was rendered by React and is not a top-level container. %s' ,
463+ isContainerReactRoot
464+ ? 'You may have accidentally passed in a React root node instead ' +
465+ 'of its container.'
466+ : 'Instead, have the parent component update its state and ' +
467+ 'rerender in order to remove this component.' ,
468+ ) ;
469+ }
439470 }
440- }
441471
442- return false ;
472+ return false ;
473+ }
443474 }
444475}
0 commit comments