diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index 7071f32b75e48..6067ba010d4f8 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -330,7 +330,6 @@ function normalizeMarkupForTextOrAttribute(markup: mixed): string { export function checkForUnmatchedText( serverText: string, clientText: string | number | bigint, - isConcurrentMode: boolean, shouldWarnDev: boolean, ) { const normalizedClientText = normalizeMarkupForTextOrAttribute(clientText); @@ -352,7 +351,7 @@ export function checkForUnmatchedText( } } - if (isConcurrentMode && enableClientRenderFallbackOnTextMismatch) { + if (enableClientRenderFallbackOnTextMismatch) { // In concurrent roots, we throw when there's a text mismatch and revert to // client rendering, up to the nearest Suspense boundary. throw new Error('Text content does not match server-rendered HTML.'); @@ -2746,7 +2745,6 @@ export function diffHydratedProperties( domElement: Element, tag: string, props: Object, - isConcurrentMode: boolean, shouldWarnDev: boolean, hostContext: HostContext, ): void { @@ -2865,14 +2863,9 @@ export function diffHydratedProperties( // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint if (domElement.textContent !== '' + children) { if (props.suppressHydrationWarning !== true) { - checkForUnmatchedText( - domElement.textContent, - children, - isConcurrentMode, - shouldWarnDev, - ); + checkForUnmatchedText(domElement.textContent, children, shouldWarnDev); } - if (!isConcurrentMode || !enableClientRenderFallbackOnTextMismatch) { + if (!enableClientRenderFallbackOnTextMismatch) { // We really should be patching this in the commit phase but since // this only affects legacy mode hydration which is deprecated anyway // we can get away with it. @@ -2941,11 +2934,7 @@ export function diffHydratedProperties( } } -export function diffHydratedText( - textNode: Text, - text: string, - isConcurrentMode: boolean, -): boolean { +export function diffHydratedText(textNode: Text, text: string): boolean { const isDifferent = textNode.nodeValue !== text; return isDifferent; } diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 450038eb70dd9..a06f9c00b610f 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -30,8 +30,6 @@ import type { import {NotPending} from 'react-dom-bindings/src/shared/ReactDOMFormActions'; import {getCurrentRootHostContainer} from 'react-reconciler/src/ReactFiberHostContext'; import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities'; -// TODO: Remove this deep import when we delete the legacy root API -import {ConcurrentMode, NoMode} from 'react-reconciler/src/ReactTypeOfMode'; import hasOwnProperty from 'shared/hasOwnProperty'; import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion'; @@ -1370,19 +1368,7 @@ export function hydrateInstance( // get attached. updateFiberProps(instance, props); - // TODO: Temporary hack to check if we're in a concurrent root. We can delete - // when the legacy root API is removed. - const isConcurrentMode = - ((internalInstanceHandle: Fiber).mode & ConcurrentMode) !== NoMode; - - diffHydratedProperties( - instance, - type, - props, - isConcurrentMode, - shouldWarnDev, - hostContext, - ); + diffHydratedProperties(instance, type, props, shouldWarnDev, hostContext); } export function validateHydratableTextInstance( @@ -1407,12 +1393,7 @@ export function hydrateTextInstance( ): boolean { precacheFiberNode(internalInstanceHandle, textInstance); - // TODO: Temporary hack to check if we're in a concurrent root. We can delete - // when the legacy root API is removed. - const isConcurrentMode = - ((internalInstanceHandle: Fiber).mode & ConcurrentMode) !== NoMode; - - return diffHydratedText(textInstance, text, isConcurrentMode); + return diffHydratedText(textInstance, text); } export function hydrateSuspenseInstance( @@ -1508,15 +1489,9 @@ export function didNotMatchHydratedContainerTextInstance( parentContainer: Container, textInstance: TextInstance, text: string, - isConcurrentMode: boolean, shouldWarnDev: boolean, ) { - checkForUnmatchedText( - textInstance.nodeValue, - text, - isConcurrentMode, - shouldWarnDev, - ); + checkForUnmatchedText(textInstance.nodeValue, text, shouldWarnDev); } export function didNotMatchHydratedTextInstance( @@ -1525,16 +1500,10 @@ export function didNotMatchHydratedTextInstance( parentInstance: Instance, textInstance: TextInstance, text: string, - isConcurrentMode: boolean, shouldWarnDev: boolean, ) { if (parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { - checkForUnmatchedText( - textInstance.nodeValue, - text, - isConcurrentMode, - shouldWarnDev, - ); + checkForUnmatchedText(textInstance.nodeValue, text, shouldWarnDev); } } @@ -1577,17 +1546,14 @@ export function didNotHydrateInstance( parentProps: Props, parentInstance: Instance, instance: HydratableInstance, - isConcurrentMode: boolean, ) { if (__DEV__) { - if (isConcurrentMode || parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { - if (instance.nodeType === ELEMENT_NODE) { - warnForDeletedHydratableElement(parentInstance, (instance: any)); - } else if (instance.nodeType === COMMENT_NODE) { - // TODO: warnForDeletedHydratableSuspenseBoundary - } else { - warnForDeletedHydratableText(parentInstance, (instance: any)); - } + if (instance.nodeType === ELEMENT_NODE) { + warnForDeletedHydratableElement(parentInstance, (instance: any)); + } else if (instance.nodeType === COMMENT_NODE) { + // TODO: warnForDeletedHydratableSuspenseBoundary + } else { + warnForDeletedHydratableText(parentInstance, (instance: any)); } } } @@ -1658,12 +1624,9 @@ export function didNotFindHydratableInstance( parentInstance: Instance, type: string, props: Props, - isConcurrentMode: boolean, ) { if (__DEV__) { - if (isConcurrentMode || parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { - warnForInsertedHydratedElement(parentInstance, type, props); - } + warnForInsertedHydratedElement(parentInstance, type, props); } } @@ -1672,12 +1635,9 @@ export function didNotFindHydratableTextInstance( parentProps: Props, parentInstance: Instance, text: string, - isConcurrentMode: boolean, ) { if (__DEV__) { - if (isConcurrentMode || parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { - warnForInsertedHydratedText(parentInstance, text); - } + warnForInsertedHydratedText(parentInstance, text); } } diff --git a/packages/react-dom/index.classic.fb.js b/packages/react-dom/index.classic.fb.js index d8814243b690d..b5e974f2b5f25 100644 --- a/packages/react-dom/index.classic.fb.js +++ b/packages/react-dom/index.classic.fb.js @@ -24,7 +24,6 @@ export { hydrateRoot, findDOMNode, flushSync, - hydrate, render, unmountComponentAtNode, unstable_batchedUpdates, diff --git a/packages/react-dom/index.js b/packages/react-dom/index.js index 4db349ea5bf0d..0c55c3a92219a 100644 --- a/packages/react-dom/index.js +++ b/packages/react-dom/index.js @@ -16,7 +16,6 @@ export { hydrateRoot, findDOMNode, flushSync, - hydrate, render, unmountComponentAtNode, unstable_batchedUpdates, diff --git a/packages/react-dom/index.stable.js b/packages/react-dom/index.stable.js index 36f5563fda5da..5e5a5fe275d95 100644 --- a/packages/react-dom/index.stable.js +++ b/packages/react-dom/index.stable.js @@ -14,7 +14,6 @@ export { hydrateRoot, findDOMNode, flushSync, - hydrate, render, unmountComponentAtNode, unstable_batchedUpdates, diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js index 3eae27486a097..a58f7f8529f98 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js @@ -12,7 +12,6 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils'); let React; -let ReactDOM; let ReactDOMClient; let ReactDOMServer; @@ -453,75 +452,3 @@ describe('ReactDOMServerIntegration', () => { )); }); }); - -describe('ReactDOMServerIntegration (legacy)', () => { - function initModules() { - // Reset warning cache. - jest.resetModules(); - - React = require('react'); - ReactDOM = require('react-dom'); - ReactDOMServer = require('react-dom/server'); - - // Make them available to the helpers. - return { - ReactDOM, - ReactDOMServer, - }; - } - - const {resetModules, expectMarkupMatch} = - ReactDOMServerIntegrationUtils(initModules); - - beforeEach(() => { - resetModules(); - }); - - // @gate !disableLegacyMode - it('legacy mode can explicitly ignore errors reconnecting different element types of children', () => - expectMarkupMatch( -
-
-
, -
- -
, - )); - - // @gate !disableLegacyMode - it('legacy mode can explicitly ignore reconnecting more children', () => - expectMarkupMatch( -
-
-
, -
-
-
-
, - )); - - // @gate !disableLegacyMode - it('legacy mode can explicitly ignore reconnecting fewer children', () => - expectMarkupMatch( -
-
-
-
, -
-
-
, - )); - - // @gate !disableLegacyMode - it('legacy mode can explicitly ignore reconnecting reordered children', () => - expectMarkupMatch( -
-
- -
, -
- -
-
, - )); -}); diff --git a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js index 6cdd82fefb011..c8ce39f86e3bf 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js @@ -1487,75 +1487,6 @@ describe('ReactDOMServerPartialHydration', () => { expect(deleted.length).toBe(1); }); - // @gate !disableLegacyMode - it('warns and replaces the boundary content in legacy mode', async () => { - let suspend = false; - let resolve; - const promise = new Promise(resolvePromise => (resolve = resolvePromise)); - const ref = React.createRef(); - - function Child() { - if (suspend) { - throw promise; - } else { - return 'Hello'; - } - } - - function App() { - return ( -
- - - - - -
- ); - } - - // Don't suspend on the server. - suspend = false; - const finalHTML = ReactDOMServer.renderToString(); - - const container = document.createElement('div'); - container.innerHTML = finalHTML; - - const span = container.getElementsByTagName('span')[0]; - - // On the client we try to hydrate. - suspend = true; - await expect(async () => { - await act(() => { - ReactDOM.hydrate(, container); - }); - }).toErrorDev( - 'Warning: Cannot hydrate Suspense in legacy mode. Switch from ' + - 'ReactDOM.hydrate(element, container) to ' + - 'ReactDOMClient.hydrateRoot(container, )' + - '.render(element) or remove the Suspense components from the server ' + - 'rendered components.' + - '\n in Suspense (at **)' + - '\n in div (at **)' + - '\n in App (at **)', - ); - - // We're now in loading state. - expect(container.textContent).toBe('Loading...'); - - const span2 = container.getElementsByTagName('span')[0]; - // This is a new node. - expect(span).not.toBe(span2); - expect(ref.current).toBe(null); - - // Resolving the promise should render the final content. - suspend = false; - await act(() => resolve()); - - // We should now have hydrated with a ref on the existing span. - expect(container.textContent).toBe('Hello'); - }); - it('can insert siblings before the dehydrated boundary', async () => { let suspend = false; const promise = new Promise(() => {}); diff --git a/packages/react-dom/src/__tests__/ReactLegacyMount-test.js b/packages/react-dom/src/__tests__/ReactLegacyMount-test.js index 52a5458697d48..6835e9a018a8f 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyMount-test.js +++ b/packages/react-dom/src/__tests__/ReactLegacyMount-test.js @@ -13,10 +13,7 @@ const {COMMENT_NODE} = require('react-dom-bindings/src/client/HTMLNodeType'); let React; let ReactDOM; -let ReactDOMServer; -let Scheduler; let ReactDOMClient; -let assertLog; let waitForAll; describe('ReactMount', () => { @@ -26,11 +23,8 @@ describe('ReactMount', () => { React = require('react'); ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); - ReactDOMServer = require('react-dom/server'); - Scheduler = require('scheduler'); const InternalTestUtils = require('internal-test-utils'); - assertLog = InternalTestUtils.assertLog; waitForAll = InternalTestUtils.waitForAll; }); @@ -138,25 +132,6 @@ describe('ReactMount', () => { expect(instance1 === instance2).toBe(true); }); - // @gate !disableLegacyMode - it('does not warn if mounting into left padded rendered markup', () => { - const container = document.createElement('container'); - container.innerHTML = ReactDOMServer.renderToString(
) + ' '; - - // This should probably ideally warn but we ignore extra markup at the root. - ReactDOM.hydrate(
, container); - }); - - // @gate !disableLegacyMode - it('should warn if mounting into right padded rendered markup', () => { - const container = document.createElement('container'); - container.innerHTML = ' ' + ReactDOMServer.renderToString(
); - - expect(() => ReactDOM.hydrate(
, container)).toErrorDev( - 'Did not expect server HTML to contain the text node " " in .', - ); - }); - // @gate !disableLegacyMode it('should not warn if mounting into non-empty node', () => { const container = document.createElement('container'); @@ -174,25 +149,6 @@ describe('ReactMount', () => { ReactDOM.render(
, iFrame.contentDocument.body); }); - // @gate !disableLegacyMode - it('should account for escaping on a checksum mismatch', () => { - const div = document.createElement('div'); - const markup = ReactDOMServer.renderToString( -
This markup contains an nbsp entity:   server text
, - ); - div.innerHTML = markup; - - expect(() => - ReactDOM.hydrate( -
This markup contains an nbsp entity:   client text
, - div, - ), - ).toErrorDev( - 'Server: "This markup contains an nbsp entity:   server text" ' + - 'Client: "This markup contains an nbsp entity:   client text"', - ); - }); - // @gate !disableLegacyMode it('should warn if render removes React-rendered children', () => { const container = document.createElement('container'); @@ -413,17 +369,6 @@ describe('ReactMount', () => { expect(container.textContent).toEqual('Bye'); }); - // @gate !disableLegacyMode - it('callback passed to legacy hydrate() API', () => { - const container = document.createElement('div'); - container.innerHTML = '
Hi
'; - ReactDOM.hydrate(
Hi
, container, () => { - Scheduler.log('callback'); - }); - expect(container.textContent).toEqual('Hi'); - assertLog(['callback']); - }); - // @gate !disableLegacyMode it('warns when unmounting with legacy API (no previous content)', async () => { const container = document.createElement('div'); diff --git a/packages/react-dom/src/__tests__/ReactLegacyRootWarnings-test.js b/packages/react-dom/src/__tests__/ReactLegacyRootWarnings-test.js index 35d63da06b48b..1eef3d140e325 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyRootWarnings-test.js +++ b/packages/react-dom/src/__tests__/ReactLegacyRootWarnings-test.js @@ -26,19 +26,4 @@ describe('ReactDOMRoot', () => { ); } }); - - // @gate !disableLegacyMode - test('deprecation warning for ReactDOM.hydrate', () => { - spyOnDev(console, 'error'); - - container.innerHTML = 'Hi'; - ReactDOM.hydrate('Hi', container); - expect(container.textContent).toEqual('Hi'); - if (__DEV__) { - expect(console.error).toHaveBeenCalledTimes(1); - expect(console.error.mock.calls[0][0]).toContain( - 'ReactDOM.hydrate has not been supported since React 18', - ); - } - }); }); diff --git a/packages/react-dom/src/__tests__/ReactRenderDocument-test.js b/packages/react-dom/src/__tests__/ReactRenderDocument-test.js index b7347470a6656..f719be6981f10 100644 --- a/packages/react-dom/src/__tests__/ReactRenderDocument-test.js +++ b/packages/react-dom/src/__tests__/ReactRenderDocument-test.js @@ -345,23 +345,5 @@ describe('rendering React components at document', () => { ]); expect(testDocument.body.innerHTML).toBe('Hello world'); }); - - // @gate !disableLegacyMode - it('supports findDOMNode on full-page components in legacy mode', () => { - const tree = ( - - - Hello World - - Hello world - - ); - - const markup = ReactDOMServer.renderToString(tree); - const testDocument = getTestDocument(markup); - const component = ReactDOM.hydrate(tree, testDocument); - expect(testDocument.body.innerHTML).toBe('Hello world'); - expect(ReactDOM.findDOMNode(component).tagName).toBe('HTML'); - }); }); }); diff --git a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js index 3ca77a661594b..e28296348afa7 100644 --- a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js @@ -505,74 +505,6 @@ describe('ReactDOMServerHydration', () => { await act(() => root.render(
)); }); - // @gate !disableLegacyMode - it('Suspense + hydration in legacy mode', () => { - const element = document.createElement('div'); - element.innerHTML = '
Hello World
'; - const div = element.firstChild.firstChild; - const ref = React.createRef(); - expect(() => - ReactDOM.hydrate( -
- -
Hello World
-
-
, - element, - ), - ).toErrorDev( - 'Warning: Did not expect server HTML to contain a
in
.', - ); - - // The content should've been client rendered and replaced the - // existing div. - expect(ref.current).not.toBe(div); - // The HTML should be the same though. - expect(element.innerHTML).toBe('
Hello World
'); - }); - - // @gate !disableLegacyMode - it('Suspense + hydration in legacy mode (at root)', () => { - const element = document.createElement('div'); - element.innerHTML = '
Hello World
'; - const div = element.firstChild; - const ref = React.createRef(); - ReactDOM.hydrate( - -
Hello World
-
, - element, - ); - - // The content should've been client rendered. - expect(ref.current).not.toBe(div); - // Unfortunately, since we don't delete the tail at the root, a duplicate will remain. - expect(element.innerHTML).toBe( - '
Hello World
Hello World
', - ); - }); - - // @gate !disableLegacyMode - it('Suspense + hydration in legacy mode with no fallback', () => { - const element = document.createElement('div'); - element.innerHTML = '
Hello World
'; - const div = element.firstChild; - const ref = React.createRef(); - ReactDOM.hydrate( - -
Hello World
-
, - element, - ); - - // The content should've been client rendered. - expect(ref.current).not.toBe(div); - // Unfortunately, since we don't delete the tail at the root, a duplicate will remain. - expect(element.innerHTML).toBe( - '
Hello World
Hello World
', - ); - }); - // regression test for https://github.com/facebook/react/issues/17170 it('should not warn if dangerouslySetInnerHtml=undefined', async () => { const domElement = document.createElement('div'); diff --git a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js index e9c4479b028fb..015942131d01d 100644 --- a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js +++ b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js @@ -52,15 +52,11 @@ module.exports = function (initModules) { async function asyncReactDOMRender(reactElement, domElement, forceHydrate) { if (forceHydrate) { await act(() => { - if (ReactDOMClient) { - ReactDOMClient.hydrateRoot(domElement, reactElement, { - onRecoverableError: () => { - // TODO: assert on recoverable error count. - }, - }); - } else { - ReactDOM.hydrate(reactElement, domElement); - } + ReactDOMClient.hydrateRoot(domElement, reactElement, { + onRecoverableError: () => { + // TODO: assert on recoverable error count. + }, + }); }); } else { await act(() => { diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js index 78fffeb41cb34..9f9ea849fd66d 100644 --- a/packages/react-dom/src/client/ReactDOM.js +++ b/packages/react-dom/src/client/ReactDOM.js @@ -21,7 +21,6 @@ import type { import { findDOMNode, render, - hydrate, unstable_renderSubtreeIntoContainer, unmountComponentAtNode, } from './ReactDOMLegacy'; @@ -172,7 +171,6 @@ export { ReactVersion as version, // Disabled behind disableLegacyReactDOMAPIs findDOMNode, - hydrate, render, unmountComponentAtNode, // exposeConcurrentModeAPIs diff --git a/packages/react-dom/src/client/ReactDOMLegacy.js b/packages/react-dom/src/client/ReactDOMLegacy.js index 64fef73640b10..50cb6fbf94b10 100644 --- a/packages/react-dom/src/client/ReactDOMLegacy.js +++ b/packages/react-dom/src/client/ReactDOMLegacy.js @@ -260,54 +260,6 @@ export function findDOMNode( return findHostInstance(componentOrElement); } -export function hydrate( - element: React$Node, - container: Container, - callback: ?Function, -): React$Component | PublicInstance | null { - if (disableLegacyMode) { - if (__DEV__) { - console.error( - 'ReactDOM.hydrate was removed in React 19. Use hydrateRoot instead', - ); - } - throw new Error('ReactDOM: Unsupported Legacy Mode API.'); - } - if (__DEV__) { - console.error( - 'ReactDOM.hydrate has not been supported since React 18. Use hydrateRoot ' + - '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.hydrate() on a container that was previously ' + - 'passed to ReactDOMClient.createRoot(). This is not supported. ' + - 'Did you mean to call hydrateRoot(container, element)?', - ); - } - } - // TODO: throw or warn if we couldn't hydrate? - return legacyRenderSubtreeIntoContainer( - null, - element, - container, - true, - callback, - ); -} - export function render( element: React$Element, container: Container, diff --git a/packages/react-dom/unstable_testing.classic.fb.js b/packages/react-dom/unstable_testing.classic.fb.js index 6dd68f3669dc3..9958b22cc3277 100644 --- a/packages/react-dom/unstable_testing.classic.fb.js +++ b/packages/react-dom/unstable_testing.classic.fb.js @@ -11,7 +11,6 @@ export { createPortal, findDOMNode, flushSync, - hydrate, render, unmountComponentAtNode, unstable_batchedUpdates, diff --git a/packages/react-dom/unstable_testing.js b/packages/react-dom/unstable_testing.js index 9729a427e4aa6..080b7340d11b2 100644 --- a/packages/react-dom/unstable_testing.js +++ b/packages/react-dom/unstable_testing.js @@ -11,7 +11,6 @@ export { createPortal, findDOMNode, flushSync, - hydrate, render, unmountComponentAtNode, unstable_batchedUpdates, diff --git a/packages/react-dom/unstable_testing.stable.js b/packages/react-dom/unstable_testing.stable.js index 453e8b4fdece7..855f6f1fc006a 100644 --- a/packages/react-dom/unstable_testing.stable.js +++ b/packages/react-dom/unstable_testing.stable.js @@ -11,7 +11,6 @@ export { createPortal, findDOMNode, flushSync, - hydrate, render, unmountComponentAtNode, unstable_batchedUpdates, diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js index 194bababd644d..ce909b802530a 100644 --- a/packages/react-reconciler/src/ReactFiber.js +++ b/packages/react-reconciler/src/ReactFiber.js @@ -849,12 +849,6 @@ export function createFiberFromText( return fiber; } -export function createFiberFromHostInstanceForDeletion(): Fiber { - const fiber = createFiber(HostComponent, null, null, NoMode); - fiber.elementType = 'DELETED'; - return fiber; -} - export function createFiberFromDehydratedFragment( dehydratedNode: SuspenseInstance, ): Fiber { diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 0b788996bd10b..28e04f7c4b870 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -141,7 +141,6 @@ import { import { NoLane, NoLanes, - SyncLane, OffscreenLane, DefaultHydrationLane, SomeRetryLane, @@ -2743,18 +2742,7 @@ function mountDehydratedSuspenseComponent( ): null | Fiber { // During the first pass, we'll bail out and not drill into the children. // Instead, we'll leave the content in place and try to hydrate it later. - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - if (__DEV__) { - console.error( - 'Cannot hydrate Suspense in legacy mode. Switch from ' + - 'ReactDOM.hydrate(element, container) to ' + - 'ReactDOMClient.hydrateRoot(container, )' + - '.render(element) or remove the Suspense components from ' + - 'the server rendered components.', - ); - } - workInProgress.lanes = laneToLanes(SyncLane); - } else if (isSuspenseInstanceFallback(suspenseInstance)) { + if (isSuspenseInstanceFallback(suspenseInstance)) { // This is a client-only boundary. Since we won't get any content from the server // for this, we need to schedule that at a higher priority based on when it would // have timed out. In theory we could render it in this pass but it would have the @@ -2794,15 +2782,6 @@ function updateDehydratedSuspenseComponent( // but after we've already committed once. warnIfHydrating(); - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - null, - ); - } - if (isSuspenseInstanceFallback(suspenseInstance)) { // This boundary is in a permanent fallback state. In this case, we'll never // get an update and we'll never be able to hydrate the final content. Let's just try the diff --git a/packages/react-reconciler/src/ReactFiberHydrationContext.js b/packages/react-reconciler/src/ReactFiberHydrationContext.js index 90d87e13d7b33..11cb591ec9a8b 100644 --- a/packages/react-reconciler/src/ReactFiberHydrationContext.js +++ b/packages/react-reconciler/src/ReactFiberHydrationContext.js @@ -8,7 +8,6 @@ */ import type {Fiber} from './ReactInternalTypes'; -import {NoMode, ConcurrentMode} from './ReactTypeOfMode'; import type { Instance, TextInstance, @@ -28,19 +27,9 @@ import { HostRoot, SuspenseComponent, } from './ReactWorkTags'; -import { - ChildDeletion, - Placement, - Hydrating, - NoFlags, - DidCapture, -} from './ReactFiberFlags'; import {enableClientRenderFallbackOnTextMismatch} from 'shared/ReactFeatureFlags'; -import { - createFiberFromHostInstanceForDeletion, - createFiberFromDehydratedFragment, -} from './ReactFiber'; +import {createFiberFromDehydratedFragment} from './ReactFiber'; import { shouldSetTextContent, supportsHydration, @@ -168,14 +157,11 @@ function warnUnhydratedInstance( } case HostSingleton: case HostComponent: { - const isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode; didNotHydrateInstance( returnFiber.type, returnFiber.memoizedProps, returnFiber.stateNode, instance, - // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode, ); break; } @@ -192,23 +178,6 @@ function warnUnhydratedInstance( } } -function deleteHydratableInstance( - returnFiber: Fiber, - instance: HydratableInstance, -) { - const childToDelete = createFiberFromHostInstanceForDeletion(); - childToDelete.stateNode = instance; - childToDelete.return = returnFiber; - - const deletions = returnFiber.deletions; - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); - } -} - function warnNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) { if (__DEV__) { if (didSuspendOrErrorDEV) { @@ -257,30 +226,22 @@ function warnNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) { case HostComponent: { const type = fiber.type; const props = fiber.pendingProps; - const isConcurrentMode = - (returnFiber.mode & ConcurrentMode) !== NoMode; didNotFindHydratableInstance( parentType, parentProps, parentInstance, type, props, - // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode, ); break; } case HostText: { const text = fiber.pendingProps; - const isConcurrentMode = - (returnFiber.mode & ConcurrentMode) !== NoMode; didNotFindHydratableTextInstance( parentType, parentProps, parentInstance, text, - // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode, ); break; } @@ -330,9 +291,6 @@ function warnNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) { } } } -function insertNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) { - fiber.flags = (fiber.flags & ~Hydrating) | Placement; -} function tryHydrateInstance(fiber: Fiber, nextInstance: any) { // fiber is a HostComponent Fiber @@ -400,13 +358,6 @@ function tryHydrateSuspense(fiber: Fiber, nextInstance: any) { return false; } -function shouldClientRenderOnMismatch(fiber: Fiber) { - return ( - (fiber.mode & ConcurrentMode) !== NoMode && - (fiber.flags & DidCapture) === NoFlags - ); -} - function throwOnHydrationMismatch(fiber: Fiber) { throw new Error( 'Hydration failed because the initial UI does not match what was ' + @@ -447,60 +398,12 @@ function tryToClaimNextHydratableInstance(fiber: Fiber): void { currentHostContext, ); - const initialInstance = nextHydratableInstance; const nextInstance = nextHydratableInstance; - if (!nextInstance) { - if (shouldClientRenderOnMismatch(fiber)) { - if (shouldKeepWarning) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - } - throwOnHydrationMismatch(fiber); - } - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance((hydrationParentFiber: any), fiber); + if (!nextInstance || !tryHydrateInstance(fiber, nextInstance)) { if (shouldKeepWarning) { warnNonHydratedInstance((hydrationParentFiber: any), fiber); } - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - const firstAttemptedInstance = nextInstance; - if (!tryHydrateInstance(fiber, nextInstance)) { - if (shouldClientRenderOnMismatch(fiber)) { - if (shouldKeepWarning) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - } - throwOnHydrationMismatch(fiber); - } - // If we can't hydrate this instance let's try the next one. - // We use this as a heuristic. It's based on intuition and not data so it - // might be flawed or unnecessary. - nextHydratableInstance = getNextHydratableSibling(nextInstance); - const prevHydrationParentFiber: Fiber = (hydrationParentFiber: any); - if ( - !nextHydratableInstance || - !tryHydrateInstance(fiber, nextHydratableInstance) - ) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance((hydrationParentFiber: any), fiber); - if (shouldKeepWarning) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - } - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - // We matched the next one, we'll now assume that the first one was - // superfluous and we'll delete it. Since we can't eagerly delete it - // we'll have to schedule a deletion. To do that, this node needs a dummy - // fiber associated with it. - if (shouldKeepWarning) { - warnUnhydratedInstance(prevHydrationParentFiber, firstAttemptedInstance); - } - deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); + throwOnHydrationMismatch(fiber); } } @@ -515,63 +418,12 @@ function tryToClaimNextHydratableTextInstance(fiber: Fiber): void { const currentHostContext = getHostContext(); shouldKeepWarning = validateHydratableTextInstance(text, currentHostContext); - const initialInstance = nextHydratableInstance; const nextInstance = nextHydratableInstance; - if (!nextInstance) { - // We exclude non hydrabable text because we know there are no matching hydratables. - // We either throw or insert depending on the render mode. - if (shouldClientRenderOnMismatch(fiber)) { - if (shouldKeepWarning) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - } - throwOnHydrationMismatch(fiber); - } - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance((hydrationParentFiber: any), fiber); + if (!nextInstance || !tryHydrateText(fiber, nextInstance)) { if (shouldKeepWarning) { warnNonHydratedInstance((hydrationParentFiber: any), fiber); } - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - const firstAttemptedInstance = nextInstance; - if (!tryHydrateText(fiber, nextInstance)) { - if (shouldClientRenderOnMismatch(fiber)) { - if (shouldKeepWarning) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - } - throwOnHydrationMismatch(fiber); - } - // If we can't hydrate this instance let's try the next one. - // We use this as a heuristic. It's based on intuition and not data so it - // might be flawed or unnecessary. - nextHydratableInstance = getNextHydratableSibling(nextInstance); - const prevHydrationParentFiber: Fiber = (hydrationParentFiber: any); - - if ( - !nextHydratableInstance || - !tryHydrateText(fiber, nextHydratableInstance) - ) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance((hydrationParentFiber: any), fiber); - if (shouldKeepWarning) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - } - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - // We matched the next one, we'll now assume that the first one was - // superfluous and we'll delete it. Since we can't eagerly delete it - // we'll have to schedule a deletion. To do that, this node needs a dummy - // fiber associated with it. - if (shouldKeepWarning) { - warnUnhydratedInstance(prevHydrationParentFiber, firstAttemptedInstance); - } - deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); + throwOnHydrationMismatch(fiber); } } @@ -579,51 +431,10 @@ function tryToClaimNextHydratableSuspenseInstance(fiber: Fiber): void { if (!isHydrating) { return; } - const initialInstance = nextHydratableInstance; const nextInstance = nextHydratableInstance; - if (!nextInstance) { - if (shouldClientRenderOnMismatch(fiber)) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - throwOnHydrationMismatch(fiber); - } - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance((hydrationParentFiber: any), fiber); + if (!nextInstance || !tryHydrateSuspense(fiber, nextInstance)) { warnNonHydratedInstance((hydrationParentFiber: any), fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - const firstAttemptedInstance = nextInstance; - if (!tryHydrateSuspense(fiber, nextInstance)) { - if (shouldClientRenderOnMismatch(fiber)) { - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - throwOnHydrationMismatch(fiber); - } - // If we can't hydrate this instance let's try the next one. - // We use this as a heuristic. It's based on intuition and not data so it - // might be flawed or unnecessary. - nextHydratableInstance = getNextHydratableSibling(nextInstance); - const prevHydrationParentFiber: Fiber = (hydrationParentFiber: any); - - if ( - !nextHydratableInstance || - !tryHydrateSuspense(fiber, nextHydratableInstance) - ) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance((hydrationParentFiber: any), fiber); - warnNonHydratedInstance((hydrationParentFiber: any), fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - // We matched the next one, we'll now assume that the first one was - // superfluous and we'll delete it. Since we can't eagerly delete it - // we'll have to schedule a deletion. To do that, this node needs a dummy - // fiber associated with it. - warnUnhydratedInstance(prevHydrationParentFiber, firstAttemptedInstance); - deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); + throwOnHydrationMismatch(fiber); } } @@ -703,17 +514,13 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): boolean { switch (returnFiber.tag) { case HostRoot: { const parentContainer = returnFiber.stateNode.containerInfo; - const isConcurrentMode = - (returnFiber.mode & ConcurrentMode) !== NoMode; didNotMatchHydratedContainerTextInstance( parentContainer, textInstance, textContent, - // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode, shouldWarnIfMismatchDev, ); - if (isConcurrentMode && enableClientRenderFallbackOnTextMismatch) { + if (enableClientRenderFallbackOnTextMismatch) { // In concurrent mode we never update the mismatched text, // even if the error was ignored. return false; @@ -725,19 +532,15 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): boolean { const parentType = returnFiber.type; const parentProps = returnFiber.memoizedProps; const parentInstance = returnFiber.stateNode; - const isConcurrentMode = - (returnFiber.mode & ConcurrentMode) !== NoMode; didNotMatchHydratedTextInstance( parentType, parentProps, parentInstance, textInstance, textContent, - // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode, shouldWarnIfMismatchDev, ); - if (isConcurrentMode && enableClientRenderFallbackOnTextMismatch) { + if (enableClientRenderFallbackOnTextMismatch) { // In concurrent mode we never update the mismatched text, // even if the error was ignored. return false; @@ -861,18 +664,10 @@ function popHydrationState(fiber: Fiber): boolean { } } if (shouldClear) { - let nextInstance = nextHydratableInstance; + const nextInstance = nextHydratableInstance; if (nextInstance) { - if (shouldClientRenderOnMismatch(fiber)) { - warnIfUnhydratedTailNodes(fiber); - throwOnHydrationMismatch(fiber); - } else { - while (nextInstance) { - warnUnhydratedInstance(fiber, nextInstance); - deleteHydratableInstance(fiber, nextInstance); - nextInstance = getNextHydratableSibling(nextInstance); - } - } + warnIfUnhydratedTailNodes(fiber); + throwOnHydrationMismatch(fiber); } } popToNextHostParent(fiber);