Repository: facebook/react
Pull request: remove unstable_renderSubtreeIntoContainer

remove unstable_renderSubtreeIntoContainer

This is finally no longer used and can be deleted.


Changed files:
filename: packages/react-dom/src/ReactDOMFB.js
patch: @@ -43,6 +43,5 @@ export {
   render,
   unstable_batchedUpdates,
   findDOMNode,
-  unstable_renderSubtreeIntoContainer,
   unmountComponentAtNode,
 } from './client/ReactDOMRootFB';

filename: packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js
patch: @@ -1,353 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @emails react-core
- */
-
-'use strict';
-
-const React = require('react');
-const PropTypes = require('prop-types');
-const ReactDOM = require('react-dom');
-const ReactDOMClient = require('react-dom/client');
-const act = require('internal-test-utils').act;
-const renderSubtreeIntoContainer =
-  require('react-dom').unstable_renderSubtreeIntoContainer;
-
-describe('renderSubtreeIntoContainer', () => {
-  // @gate !disableLegacyContext
-  // @gate !disableLegacyMode
-  it('should pass context when rendering subtree elsewhere', () => {
-    const portal = document.createElement('div');
-
-    class Component extends React.Component {
-      static contextTypes = {
-        foo: PropTypes.string.isRequired,
-      };
-
-      render() {
-        return <div>{this.context.foo}</div>;
-      }
-    }
-
-    class Parent extends React.Component {
-      static childContextTypes = {
-        foo: PropTypes.string.isRequired,
-      };
-
-      getChildContext() {
-        return {
-          foo: 'bar',
-        };
-      }
-
-      render() {
-        return null;
-      }
-
-      componentDidMount() {
-        expect(
-          function () {
-            renderSubtreeIntoContainer(this, <Component />, portal);
-          }.bind(this),
-        ).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-    }
-
-    const container = document.createElement('div');
-    ReactDOM.render(<Parent />, container);
-    expect(portal.firstChild.innerHTML).toBe('bar');
-  });
-
-  // @gate !disableLegacyContext
-  // @gate !disableLegacyMode
-  it('should update context if it changes due to setState', async () => {
-    const container = document.createElement('div');
-    document.body.appendChild(container);
-    const portal = document.createElement('div');
-
-    class Component extends React.Component {
-      static contextTypes = {
-        foo: PropTypes.string.isRequired,
-        getFoo: PropTypes.func.isRequired,
-      };
-
-      render() {
-        return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
-      }
-    }
-
-    class Parent extends React.Component {
-      static childContextTypes = {
-        foo: PropTypes.string.isRequired,
-        getFoo: PropTypes.func.isRequired,
-      };
-
-      state = {
-        bar: 'initial',
-      };
-
-      getChildContext() {
-        return {
-          foo: this.state.bar,
-          getFoo: () => this.state.bar,
-        };
-      }
-
-      render() {
-        return null;
-      }
-
-      componentDidMount() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <Component />, portal);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-
-      componentDidUpdate() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <Component />, portal);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-    }
-    const root = ReactDOMClient.createRoot(container);
-    const parentRef = React.createRef();
-    await act(async () => {
-      root.render(<Parent ref={parentRef} />);
-    });
-    const instance = parentRef.current;
-
-    expect(portal.firstChild.innerHTML).toBe('initial-initial');
-    await act(async () => {
-      instance.setState({bar: 'changed'});
-    });
-    expect(portal.firstChild.innerHTML).toBe('changed-changed');
-  });
-
-  // @gate !disableLegacyContext
-  // @gate !disableLegacyMode
-  it('should update context if it changes due to re-render', async () => {
-    const container = document.createElement('div');
-    document.body.appendChild(container);
-    const portal = document.createElement('div');
-
-    class Component extends React.Component {
-      static contextTypes = {
-        foo: PropTypes.string.isRequired,
-        getFoo: PropTypes.func.isRequired,
-      };
-
-      render() {
-        return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
-      }
-    }
-
-    class Parent extends React.Component {
-      static childContextTypes = {
-        foo: PropTypes.string.isRequired,
-        getFoo: PropTypes.func.isRequired,
-      };
-
-      getChildContext() {
-        return {
-          foo: this.props.bar,
-          getFoo: () => this.props.bar,
-        };
-      }
-
-      render() {
-        return null;
-      }
-
-      componentDidMount() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <Component />, portal);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-
-      componentDidUpdate() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <Component />, portal);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-    }
-
-    const root = ReactDOMClient.createRoot(container);
-    await act(async () => {
-      root.render(<Parent bar="initial" />);
-    });
-    expect(portal.firstChild.innerHTML).toBe('initial-initial');
-    await act(async () => {
-      root.render(<Parent bar="changed" />);
-    });
-    expect(portal.firstChild.innerHTML).toBe('changed-changed');
-  });
-
-  // @gate !disableLegacyMode
-  it('should render portal with non-context-provider parent', async () => {
-    const container = document.createElement('div');
-    document.body.appendChild(container);
-    const portal = document.createElement('div');
-
-    class Parent extends React.Component {
-      render() {
-        return null;
-      }
-
-      componentDidMount() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <div>hello</div>, portal);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-    }
-
-    const root = ReactDOMClient.createRoot(container);
-    await act(async () => {
-      root.render(<Parent bar="initial" />);
-    });
-    expect(portal.firstChild.innerHTML).toBe('hello');
-  });
-
-  // @gate !disableLegacyContext
-  // @gate !disableLegacyMode
-  it('should get context through non-context-provider parent', async () => {
-    const container = document.createElement('div');
-    document.body.appendChild(container);
-    const portal = document.createElement('div');
-
-    class Parent extends React.Component {
-      render() {
-        return <Middle />;
-      }
-      getChildContext() {
-        return {value: this.props.value};
-      }
-      static childContextTypes = {
-        value: PropTypes.string.isRequired,
-      };
-    }
-
-    class Middle extends React.Component {
-      render() {
-        return null;
-      }
-      componentDidMount() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <Child />, portal);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-    }
-
-    class Child extends React.Component {
-      static contextTypes = {
-        value: PropTypes.string.isRequired,
-      };
-      render() {
-        return <div>{this.context.value}</div>;
-      }
-    }
-
-    const root = ReactDOMClient.createRoot(container);
-    await act(async () => {
-      root.render(<Parent value="foo" />);
-    });
-    expect(portal.textContent).toBe('foo');
-  });
-
-  // @gate !disableLegacyContext
-  // @gate !disableLegacyMode
-  it('should get context through middle non-context-provider layer', async () => {
-    const container = document.createElement('div');
-    document.body.appendChild(container);
-    const portal1 = document.createElement('div');
-    const portal2 = document.createElement('div');
-
-    class Parent extends React.Component {
-      render() {
-        return null;
-      }
-      getChildContext() {
-        return {value: this.props.value};
-      }
-      componentDidMount() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <Middle />, portal1);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-      static childContextTypes = {
-        value: PropTypes.string.isRequired,
-      };
-    }
-
-    class Middle extends React.Component {
-      render() {
-        return null;
-      }
-      componentDidMount() {
-        expect(() => {
-          renderSubtreeIntoContainer(this, <Child />, portal2);
-        }).toErrorDev(
-          'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18',
-        );
-      }
-    }
-
-    class Child extends React.Component {
-      static contextTypes = {
-        value: PropTypes.string.isRequired,
-      };
-      render() {
-        return <div>{this.context.value}</div>;
-      }
-    }
-
-    const root = ReactDOMClient.createRoot(container);
-    await act(async () => {
-      root.render(<Parent value="foo" />);
-    });
-    expect(portal2.textContent).toBe('foo');
-  });
-
-  // @gate !disableLegacyMode
-  it('legacy test: fails gracefully when mixing React 15 and 16', () => {
-    class C extends React.Component {
-      render() {
-        return <div />;
-      }
-    }
-    const c = ReactDOM.render(<C />, document.createElement('div'));
-    // React 15 calls this:
-    // https://github.com/facebook/react/blob/77b71fc3c4/src/renderers/dom/client/ReactMount.js#L478-L479
-    expect(() => {
-      c._reactInternalInstance._processChildContext({});
-    }).toThrow(
-      __DEV__
-        ? '_processChildContext is not available in React 16+. This likely ' +
-            'means you have multiple copies of React and are attempting to nest ' +
-            'a React 15 tree inside a React 16 tree using ' +
-            "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
-            'make sure you have only one copy of React (and ideally, switch to ' +
-            'ReactDOM.createPortal).'
-        : "Cannot read property '_processChildContext' of undefined",
-    );
-  });
-});

filename: packages/react-dom/src/client/ReactDOMRootFB.js
patch: @@ -59,7 +59,6 @@ import {
 } from 'react-reconciler/src/ReactFiberReconciler';
 import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
 import getComponentNameFromType from 'shared/getComponentNameFromType';
-import {has as hasInstance} from 'shared/ReactInstanceMap';
 
 import {
   current as currentOwner,
@@ -420,46 +419,6 @@ export function render(
   );
 }
 
-export function unstable_renderSubtreeIntoContainer(
-  parentComponent: React$Component<any, any>,
-  element: React$Element<any>,
-  containerNode: Container,
-  callback: ?Function,
-): React$Component<any, any> | PublicInstance | null {
-  if (disableLegacyMode) {
-    if (__DEV__) {
-      console.error(
-        'ReactDOM.unstable_renderSubtreeIntoContainer() was removed in React 19. Consider using a portal instead.',
-      );
-    }
-    throw new Error('ReactDOM: Unsupported Legacy Mode API.');
-  }
-  if (__DEV__) {
-    console.error(
-      'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported ' +
-        'since React 18. Consider using a portal instead. Until you switch to ' +
-        "the createRoot API, your app will behave as if it's running React " +
-        '17. Learn more: https://react.dev/link/switch-to-createroot',
-    );
-  }
-
-  if (!isValidContainerLegacy(containerNode)) {
-    throw new Error('Target container is not a DOM element.');
-  }
-
-  if (parentComponent == null || !hasInstance(parentComponent)) {
-    throw new Error('parentComponent must be a valid React Component');
-  }
-
-  return legacyRenderSubtreeIntoContainer(
-    parentComponent,
-    element,
-    containerNode,
-    false,
-    callback,
-  );
-}
-
 export function unmountComponentAtNode(container: Container): boolean {
   if (disableLegacyMode) {
     if (__DEV__) {

filename: packages/react-reconciler/src/ReactFiberClassComponent.js
patch: @@ -73,9 +73,7 @@ import {
   setIsStrictModeForDevtools,
 } from './ReactFiberDevToolsHook';
 
-const fakeInternalInstance: {
-  _processChildContext?: () => empty,
-} = {};
+const fakeInternalInstance = {};
 
 let didWarnAboutStateAssignmentForComponent;
 let didWarnAboutUninitializedState;
@@ -98,24 +96,6 @@ if (__DEV__) {
   didWarnAboutInvalidateContextType = new Set<string>();
   didWarnOnInvalidCallback = new Set<string>();
 
-  // This is so gross but it's at least non-critical and can be removed if
-  // it causes problems. This is meant to give a nicer error message for
-  // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component,
-  // ...)) which otherwise throws a "_processChildContext is not a function"
-  // exception.
-  Object.defineProperty(fakeInternalInstance, '_processChildContext', {
-    enumerable: false,
-    value: function (): empty {
-      throw new Error(
-        '_processChildContext is not available in React 16+. This likely ' +
-          'means you have multiple copies of React and are attempting to nest ' +
-          'a React 15 tree inside a React 16 tree using ' +
-          "unstable_renderSubtreeIntoContainer, which isn't supported. Try " +
-          'to make sure you have only one copy of React (and ideally, switch ' +
-          'to ReactDOM.createPortal).',
-      );
-    },
-  });
   Object.freeze(fakeInternalInstance);
 }
 

filename: packages/shared/ReactInstanceMap.js
patch: @@ -15,23 +15,10 @@
  * If this becomes an actual Map, that will break.
  */
 
-/**
- * This API should be called `delete` but we'd have to make sure to always
- * transform these to strings for IE support. When this transform is fully
- * supported we can rename it.
- */
-export function remove(key) {
-  key._reactInternals = undefined;
-}
-
 export function get(key) {
   return key._reactInternals;
 }
 
-export function has(key) {
-  return key._reactInternals !== undefined;
-}
-
 export function set(key, value) {
   key._reactInternals = value;
 }