From c9d7d92bd53bbcc925fa87faec01b0796f7382af Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 5 Jun 2024 13:28:10 -0400 Subject: [PATCH] remove unstable_renderSubtreeIntoContainer This is finally no longer used and can be deleted. --- packages/react-dom/src/ReactDOMFB.js | 1 - .../renderSubtreeIntoContainer-test.js | 353 ------------------ .../react-dom/src/client/ReactDOMRootFB.js | 41 -- .../src/ReactFiberClassComponent.js | 22 +- packages/shared/ReactInstanceMap.js | 13 - 5 files changed, 1 insertion(+), 429 deletions(-) delete mode 100644 packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js diff --git a/packages/react-dom/src/ReactDOMFB.js b/packages/react-dom/src/ReactDOMFB.js index 409aa376d5c1c..4825c80dfb33d 100644 --- a/packages/react-dom/src/ReactDOMFB.js +++ b/packages/react-dom/src/ReactDOMFB.js @@ -43,6 +43,5 @@ export { render, unstable_batchedUpdates, findDOMNode, - unstable_renderSubtreeIntoContainer, unmountComponentAtNode, } from './client/ReactDOMRootFB'; diff --git a/packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js b/packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js deleted file mode 100644 index 4f93cd3ac89ef..0000000000000 --- a/packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js +++ /dev/null @@ -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
{this.context.foo}
; - } - } - - class Parent extends React.Component { - static childContextTypes = { - foo: PropTypes.string.isRequired, - }; - - getChildContext() { - return { - foo: 'bar', - }; - } - - render() { - return null; - } - - componentDidMount() { - expect( - function () { - renderSubtreeIntoContainer(this, , portal); - }.bind(this), - ).toErrorDev( - 'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18', - ); - } - } - - const container = document.createElement('div'); - ReactDOM.render(, 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
{this.context.foo + '-' + this.context.getFoo()}
; - } - } - - 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, , portal); - }).toErrorDev( - 'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18', - ); - } - - componentDidUpdate() { - expect(() => { - renderSubtreeIntoContainer(this, , 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(); - }); - 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
{this.context.foo + '-' + this.context.getFoo()}
; - } - } - - 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, , portal); - }).toErrorDev( - 'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18', - ); - } - - componentDidUpdate() { - expect(() => { - renderSubtreeIntoContainer(this, , portal); - }).toErrorDev( - 'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18', - ); - } - } - - const root = ReactDOMClient.createRoot(container); - await act(async () => { - root.render(); - }); - expect(portal.firstChild.innerHTML).toBe('initial-initial'); - await act(async () => { - root.render(); - }); - 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,
hello
, portal); - }).toErrorDev( - 'ReactDOM.unstable_renderSubtreeIntoContainer() has not been supported since React 18', - ); - } - } - - const root = ReactDOMClient.createRoot(container); - await act(async () => { - root.render(); - }); - 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 ; - } - getChildContext() { - return {value: this.props.value}; - } - static childContextTypes = { - value: PropTypes.string.isRequired, - }; - } - - class Middle extends React.Component { - render() { - return null; - } - componentDidMount() { - expect(() => { - renderSubtreeIntoContainer(this, , 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
{this.context.value}
; - } - } - - const root = ReactDOMClient.createRoot(container); - await act(async () => { - root.render(); - }); - 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, , 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, , 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
{this.context.value}
; - } - } - - const root = ReactDOMClient.createRoot(container); - await act(async () => { - root.render(); - }); - 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
; - } - } - const c = ReactDOM.render(, 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", - ); - }); -}); diff --git a/packages/react-dom/src/client/ReactDOMRootFB.js b/packages/react-dom/src/client/ReactDOMRootFB.js index 64a1cf12ac734..1e5609726688f 100644 --- a/packages/react-dom/src/client/ReactDOMRootFB.js +++ b/packages/react-dom/src/client/ReactDOMRootFB.js @@ -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, - element: React$Element, - containerNode: Container, - callback: ?Function, -): React$Component | 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__) { diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index 6bf04da4b41b6..5a7692949b524 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -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(); didWarnOnInvalidCallback = new Set(); - // 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); } diff --git a/packages/shared/ReactInstanceMap.js b/packages/shared/ReactInstanceMap.js index 7eab16f55b690..2ad235c7a5f8d 100644 --- a/packages/shared/ReactInstanceMap.js +++ b/packages/shared/ReactInstanceMap.js @@ -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; }