From 17c3c268228da172e13d777feefbd98a91055b06 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Fri, 3 Jan 2025 16:01:30 -0500 Subject: [PATCH] [fb][react-dom] remove render/unmount from ReactDOMRootFB --- .../src/client/ReactDOMContainer.js | 13 - .../react-dom/src/client/ReactDOMRootFB.js | 332 +----------------- .../src/ReactFiberReconciler.js | 15 +- .../src/ReactFiberTreeReflection.js | 34 -- 4 files changed, 2 insertions(+), 392 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactDOMContainer.js b/packages/react-dom-bindings/src/client/ReactDOMContainer.js index 0af0f13a790a8..df9bcfb443803 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMContainer.js +++ b/packages/react-dom-bindings/src/client/ReactDOMContainer.js @@ -27,16 +27,3 @@ export function isValidContainer(node: any): boolean { (node: any).nodeValue === ' react-mount-point-unstable ')) ); } - -// TODO: Remove this function which also includes comment nodes. -// We only use it in places that are currently more relaxed. -export function isValidContainerLegacy(node: any): boolean { - return !!( - node && - (node.nodeType === ELEMENT_NODE || - node.nodeType === DOCUMENT_NODE || - node.nodeType === DOCUMENT_FRAGMENT_NODE || - (node.nodeType === COMMENT_NODE && - (node: any).nodeValue === ' react-mount-point-unstable ')) - ); -} diff --git a/packages/react-dom/src/client/ReactDOMRootFB.js b/packages/react-dom/src/client/ReactDOMRootFB.js index 1e5609726688f..5250aa2de4bf8 100644 --- a/packages/react-dom/src/client/ReactDOMRootFB.js +++ b/packages/react-dom/src/client/ReactDOMRootFB.js @@ -15,8 +15,6 @@ import type { HydrateRootOptions, } from './ReactDOMRoot'; -import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes'; - import type { Container, PublicInstance, @@ -27,37 +25,15 @@ import { hydrateRoot as hydrateRootImpl, } from './ReactDOMRoot'; -import {disableLegacyMode} from 'shared/ReactFeatureFlags'; -import {clearContainer} from 'react-dom-bindings/src/client/ReactFiberConfigDOM'; -import { - getInstanceFromNode, - isContainerMarkedAsRoot, - markContainerAsRoot, - unmarkContainerAsRoot, -} from 'react-dom-bindings/src/client/ReactDOMComponentTree'; -import {listenToAllSupportedEvents} from 'react-dom-bindings/src/events/DOMPluginEventSystem'; -import {isValidContainerLegacy} from 'react-dom-bindings/src/client/ReactDOMContainer'; -import { - DOCUMENT_NODE, - ELEMENT_NODE, - COMMENT_NODE, -} from 'react-dom-bindings/src/client/HTMLNodeType'; +import {ELEMENT_NODE} from 'react-dom-bindings/src/client/HTMLNodeType'; import { batchedUpdates, - createContainer, - createHydrationContainer, - findHostInstanceWithNoPortals, - updateContainer, - updateContainerSync, - flushSyncWork, - getPublicRootInstance, findHostInstance, findHostInstanceWithWarning, defaultOnUncaughtError, defaultOnCaughtError, } from 'react-reconciler/src/ReactFiberReconciler'; -import {LegacyRoot} from 'react-reconciler/src/ReactRootTags'; import getComponentNameFromType from 'shared/getComponentNameFromType'; import { @@ -156,190 +132,6 @@ export function hydrateRoot( ); } -let topLevelUpdateWarnings; - -if (__DEV__) { - topLevelUpdateWarnings = (container: Container) => { - if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) { - const hostInstance = findHostInstanceWithNoPortals( - container._reactRootContainer.current, - ); - if (hostInstance) { - if (hostInstance.parentNode !== container) { - console.error( - 'It looks like the React-rendered content of this ' + - 'container was removed without using React. This is not ' + - 'supported and will cause errors. Instead, call ' + - 'ReactDOM.unmountComponentAtNode to empty a container.', - ); - } - } - } - - const isRootRenderedBySomeReact = !!container._reactRootContainer; - const rootEl = getReactRootElementInContainer(container); - const hasNonRootReactChild = !!(rootEl && getInstanceFromNode(rootEl)); - - if (hasNonRootReactChild && !isRootRenderedBySomeReact) { - console.error( - 'Replacing React-rendered children with a new root ' + - 'component. If you intended to update the children of this node, ' + - 'you should instead have the existing children update their state ' + - 'and render the new components instead of calling ReactDOM.render.', - ); - } - }; -} - -function getReactRootElementInContainer(container: any) { - if (!container) { - return null; - } - - if (container.nodeType === DOCUMENT_NODE) { - return container.documentElement; - } else { - return container.firstChild; - } -} - -function noopOnRecoverableError() { - // This isn't reachable because onRecoverableError isn't called in the - // legacy API. -} - -function legacyCreateRootFromDOMContainer( - container: Container, - initialChildren: ReactNodeList, - parentComponent: ?React$Component, - callback: ?Function, - isHydrationContainer: boolean, -): FiberRoot { - if (isHydrationContainer) { - if (typeof callback === 'function') { - const originalCallback = callback; - callback = function () { - const instance = getPublicRootInstance(root); - originalCallback.call(instance); - }; - } - - const root: FiberRoot = createHydrationContainer( - initialChildren, - callback, - container, - LegacyRoot, - null, // hydrationCallbacks - false, // isStrictMode - false, // concurrentUpdatesByDefaultOverride, - '', // identifierPrefix - wwwOnUncaughtError, - wwwOnCaughtError, - noopOnRecoverableError, - // TODO(luna) Support hydration later - null, - null, - ); - container._reactRootContainer = root; - markContainerAsRoot(root.current, container); - - const rootContainerElement = - container.nodeType === COMMENT_NODE ? container.parentNode : container; - // $FlowFixMe[incompatible-call] - listenToAllSupportedEvents(rootContainerElement); - - flushSyncWork(); - return root; - } else { - // First clear any existing content. - clearContainer(container); - - if (typeof callback === 'function') { - const originalCallback = callback; - callback = function () { - const instance = getPublicRootInstance(root); - originalCallback.call(instance); - }; - } - - const root = createContainer( - container, - LegacyRoot, - null, // hydrationCallbacks - false, // isStrictMode - false, // concurrentUpdatesByDefaultOverride, - '', // identifierPrefix - wwwOnUncaughtError, - wwwOnCaughtError, - noopOnRecoverableError, - null, // transitionCallbacks - ); - container._reactRootContainer = root; - markContainerAsRoot(root.current, container); - - const rootContainerElement = - container.nodeType === COMMENT_NODE ? container.parentNode : container; - // $FlowFixMe[incompatible-call] - listenToAllSupportedEvents(rootContainerElement); - - // Initial mount should not be batched. - updateContainerSync(initialChildren, root, parentComponent, callback); - flushSyncWork(); - - return root; - } -} - -function warnOnInvalidCallback(callback: mixed): void { - if (__DEV__) { - if (callback !== null && typeof callback !== 'function') { - console.error( - 'Expected the last optional `callback` argument to be a ' + - 'function. Instead received: %s.', - callback, - ); - } - } -} - -function legacyRenderSubtreeIntoContainer( - parentComponent: ?React$Component, - children: ReactNodeList, - container: Container, - forceHydrate: boolean, - callback: ?Function, -): React$Component | PublicInstance | null { - if (__DEV__) { - topLevelUpdateWarnings(container); - warnOnInvalidCallback(callback === undefined ? null : callback); - } - - const maybeRoot = container._reactRootContainer; - let root: FiberRoot; - if (!maybeRoot) { - // Initial mount - root = legacyCreateRootFromDOMContainer( - container, - children, - parentComponent, - callback, - forceHydrate, - ); - } else { - root = maybeRoot; - if (typeof callback === 'function') { - const originalCallback = callback; - callback = function () { - const instance = getPublicRootInstance(root); - originalCallback.call(instance); - }; - } - // Update - updateContainer(children, root, parentComponent, callback); - } - return getPublicRootInstance(root); -} - export function findDOMNode( componentOrElement: Element | ?React$Component, ): null | Element | Text { @@ -372,126 +164,4 @@ export function findDOMNode( return findHostInstance(componentOrElement); } -export function render( - element: React$Element, - container: Container, - callback: ?Function, -): React$Component | PublicInstance | null { - if (disableLegacyMode) { - if (__DEV__) { - console.error( - 'ReactDOM.render was removed in React 19. Use createRoot instead.', - ); - } - throw new Error('ReactDOM: Unsupported Legacy Mode API.'); - } - if (__DEV__) { - console.error( - 'ReactDOM.render has not been supported since React 18. Use createRoot ' + - 'instead. Until you switch to the new API, your app will behave as ' + - "if it's running React 17. Learn " + - 'more: https://react.dev/link/switch-to-createroot', - ); - } - - if (!isValidContainerLegacy(container)) { - throw new Error('Target container is not a DOM element.'); - } - - if (__DEV__) { - const isModernRoot = - isContainerMarkedAsRoot(container) && - container._reactRootContainer === undefined; - if (isModernRoot) { - console.error( - 'You are calling ReactDOM.render() on a container that was previously ' + - 'passed to ReactDOMClient.createRoot(). This is not supported. ' + - 'Did you mean to call root.render(element)?', - ); - } - } - return legacyRenderSubtreeIntoContainer( - null, - element, - container, - false, - callback, - ); -} - -export function unmountComponentAtNode(container: Container): boolean { - if (disableLegacyMode) { - if (__DEV__) { - console.error( - 'unmountComponentAtNode was removed in React 19. Use root.unmount() instead.', - ); - } - throw new Error('ReactDOM: Unsupported Legacy Mode API.'); - } - if (!isValidContainerLegacy(container)) { - throw new Error('Target container is not a DOM element.'); - } - - if (__DEV__) { - const isModernRoot = - isContainerMarkedAsRoot(container) && - container._reactRootContainer === undefined; - if (isModernRoot) { - console.error( - 'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' + - 'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?', - ); - } - } - - if (container._reactRootContainer) { - const root = container._reactRootContainer; - - if (__DEV__) { - const rootEl = getReactRootElementInContainer(container); - const renderedByDifferentReact = rootEl && !getInstanceFromNode(rootEl); - if (renderedByDifferentReact) { - console.error( - "unmountComponentAtNode(): The node you're attempting to unmount " + - 'was rendered by another copy of React.', - ); - } - } - - updateContainerSync(null, root, null, null); - flushSyncWork(); - // $FlowFixMe[incompatible-type] This should probably use `delete container._reactRootContainer` - container._reactRootContainer = null; - unmarkContainerAsRoot(container); - return true; - } else { - if (__DEV__) { - const rootEl = getReactRootElementInContainer(container); - const hasNonRootReactChild = !!(rootEl && getInstanceFromNode(rootEl)); - - // Check if the container itself is a React root node. - const isContainerReactRoot = - container.nodeType === ELEMENT_NODE && - isValidContainerLegacy(container.parentNode) && - // $FlowFixMe[prop-missing] - // $FlowFixMe[incompatible-use] - !!container.parentNode._reactRootContainer; - - if (hasNonRootReactChild) { - console.error( - "unmountComponentAtNode(): The node you're attempting to unmount " + - 'was rendered by React and is not a top-level container. %s', - isContainerReactRoot - ? 'You may have accidentally passed in a React root node instead ' + - 'of its container.' - : 'Instead, have the parent component update its state and ' + - 'rerender in order to remove this component.', - ); - } - } - - return false; - } -} - export {batchedUpdates as unstable_batchedUpdates}; diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index 98ef2ef93fc46..5ea201679b003 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -24,10 +24,7 @@ import type {Lane} from './ReactFiberLane'; import type {SuspenseState} from './ReactFiberSuspenseComponent'; import {LegacyRoot} from './ReactRootTags'; -import { - findCurrentHostFiber, - findCurrentHostFiberWithNoPortals, -} from './ReactFiberTreeReflection'; +import {findCurrentHostFiber} from './ReactFiberTreeReflection'; import {get as getInstance} from 'shared/ReactInstanceMap'; import { HostComponent, @@ -555,16 +552,6 @@ export {findHostInstance}; export {findHostInstanceWithWarning}; -export function findHostInstanceWithNoPortals( - fiber: Fiber, -): PublicInstance | null { - const hostFiber = findCurrentHostFiberWithNoPortals(fiber); - if (hostFiber === null) { - return null; - } - return getPublicInstance(hostFiber.stateNode); -} - let shouldErrorImpl: Fiber => ?boolean = fiber => null; export function shouldError(fiber: Fiber): ?boolean { diff --git a/packages/react-reconciler/src/ReactFiberTreeReflection.js b/packages/react-reconciler/src/ReactFiberTreeReflection.js index e0199108693e3..e8fe1e3ce10b3 100644 --- a/packages/react-reconciler/src/ReactFiberTreeReflection.js +++ b/packages/react-reconciler/src/ReactFiberTreeReflection.js @@ -19,7 +19,6 @@ import { HostHoistable, HostSingleton, HostRoot, - HostPortal, HostText, SuspenseComponent, } from './ReactWorkTags'; @@ -296,39 +295,6 @@ function findCurrentHostFiberImpl(node: Fiber): Fiber | null { return null; } -export function findCurrentHostFiberWithNoPortals(parent: Fiber): Fiber | null { - const currentParent = findCurrentFiberUsingSlowPath(parent); - return currentParent !== null - ? findCurrentHostFiberWithNoPortalsImpl(currentParent) - : null; -} - -function findCurrentHostFiberWithNoPortalsImpl(node: Fiber): Fiber | null { - // Next we'll drill down this component to find the first HostComponent/Text. - const tag = node.tag; - if ( - tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton || - tag === HostText - ) { - return node; - } - - let child = node.child; - while (child !== null) { - if (child.tag !== HostPortal) { - const match = findCurrentHostFiberWithNoPortalsImpl(child); - if (match !== null) { - return match; - } - } - child = child.sibling; - } - - return null; -} - export function isFiberSuspenseAndTimedOut(fiber: Fiber): boolean { const memoizedState = fiber.memoizedState; return (