From 392808a1f7fa2909492a742116ba8b549e862d70 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Wed, 20 Apr 2022 10:21:36 -0400 Subject: [PATCH] Land enableClientRenderFallbackOnTextMismatch flag (#24405) This flag is already enabled on all relevant surfaces. We can remove it. --- .../__tests__/ReactServerRendering-test.js | 37 ----- .../src/client/ReactDOMHostConfig.js | 25 ++- .../src/server/ReactPartialRenderer.js | 85 +++++----- .../src/ReactFiberBeginWork.new.js | 151 +++++++++--------- .../src/ReactFiberBeginWork.old.js | 151 +++++++++--------- .../src/ReactFiberCommitWork.new.js | 45 +++--- .../src/ReactFiberCommitWork.old.js | 45 +++--- .../src/ReactFiberCompleteWork.new.js | 136 ++++++++-------- .../src/ReactFiberCompleteWork.old.js | 136 ++++++++-------- .../src/ReactFiberHydrationContext.new.js | 53 +++--- .../src/ReactFiberHydrationContext.old.js | 53 +++--- .../src/ReactFiberNewContext.new.js | 11 +- .../src/ReactFiberNewContext.old.js | 11 +- .../src/ReactFiberUnwindWork.new.js | 28 ++-- .../src/ReactFiberUnwindWork.old.js | 28 ++-- .../src/ReactFiberWorkLoop.new.js | 37 ++--- .../src/ReactFiberWorkLoop.old.js | 37 ++--- packages/shared/ReactFeatureFlags.js | 1 - .../forks/ReactFeatureFlags.native-fb.js | 1 - .../forks/ReactFeatureFlags.native-oss.js | 1 - .../forks/ReactFeatureFlags.test-renderer.js | 1 - .../ReactFeatureFlags.test-renderer.native.js | 1 - .../ReactFeatureFlags.test-renderer.www.js | 1 - .../shared/forks/ReactFeatureFlags.testing.js | 1 - .../forks/ReactFeatureFlags.testing.www.js | 1 - .../shared/forks/ReactFeatureFlags.www.js | 1 - 26 files changed, 473 insertions(+), 605 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js index 0c057c5fade05..23be43a7735a5 100644 --- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js @@ -14,8 +14,6 @@ let React; let ReactDOMServer; let PropTypes; let ReactCurrentDispatcher; -const enableSuspenseServerRenderer = require('shared/ReactFeatureFlags') - .enableSuspenseServerRenderer; describe('ReactDOMServer', () => { beforeEach(() => { @@ -678,41 +676,6 @@ describe('ReactDOMServer', () => { expect(markup).toBe('
'); }); - if (!enableSuspenseServerRenderer) { - it('throws for unsupported types on the server', () => { - expect(() => { - ReactDOMServer.renderToString(); - }).toThrow('ReactDOMServer does not yet support Suspense.'); - - async function fakeImport(result) { - return {default: result}; - } - - expect(() => { - const LazyFoo = React.lazy(() => - fakeImport( - new Promise(resolve => - resolve(function Foo() { - return
; - }), - ), - ), - ); - ReactDOMServer.renderToString(); - }).toThrow('ReactDOMServer does not yet support Suspense.'); - }); - - it('throws when suspending on the server', () => { - function AsyncFoo() { - throw new Promise(() => {}); - } - - expect(() => { - ReactDOMServer.renderToString(); - }).toThrow('ReactDOMServer does not yet support Suspense.'); - }); - } - it('does not get confused by throwing null', () => { function Bad() { // eslint-disable-next-line no-throw-literal diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index d27bdff4305ab..0cf031776399e 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -63,7 +63,6 @@ import {retryIfBlockedOn} from '../events/ReactDOMEventReplaying'; import { enableClientRenderFallbackOnHydrationMismatch, - enableSuspenseServerRenderer, enableCreateEventHandleAPI, enableScopeAPI, } from 'shared/ReactFeatureFlags'; @@ -747,19 +746,17 @@ function getNextHydratable(node) { if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) { break; } - if (enableSuspenseServerRenderer) { - if (nodeType === COMMENT_NODE) { - const nodeData = (node: any).data; - if ( - nodeData === SUSPENSE_START_DATA || - nodeData === SUSPENSE_FALLBACK_START_DATA || - nodeData === SUSPENSE_PENDING_START_DATA - ) { - break; - } - if (nodeData === SUSPENSE_END_DATA) { - return null; - } + if (nodeType === COMMENT_NODE) { + const nodeData = (node: any).data; + if ( + nodeData === SUSPENSE_START_DATA || + nodeData === SUSPENSE_FALLBACK_START_DATA || + nodeData === SUSPENSE_PENDING_START_DATA + ) { + break; + } + if (nodeData === SUSPENSE_END_DATA) { + return null; } } } diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index 41c2885680437..03f5355ef0e77 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -21,7 +21,6 @@ import { warnAboutDeprecatedLifecycles, disableLegacyContext, disableModulePatternComponents, - enableSuspenseServerRenderer, enableScopeAPI, } from 'shared/ReactFeatureFlags'; import { @@ -965,21 +964,17 @@ class ReactDOMServerRenderer { outBuffer += this.render(child, frame.context, frame.domNamespace); } catch (err) { if (err != null && typeof err.then === 'function') { - if (enableSuspenseServerRenderer) { - if (this.suspenseDepth <= 0) { - throw new Error( - // TODO: include component name. This is a bit tricky with current factoring. - 'A React component suspended while rendering, but no fallback UI was specified.\n' + - '\n' + - 'Add a component higher in the tree to ' + - 'provide a loading indicator or placeholder to display.', - ); - } - - suspended = true; - } else { - throw new Error('ReactDOMServer does not yet support Suspense.'); + if (this.suspenseDepth <= 0) { + throw new Error( + // TODO: include component name. This is a bit tricky with current factoring. + 'A React component suspended while rendering, but no fallback UI was specified.\n' + + '\n' + + 'Add a component higher in the tree to ' + + 'provide a loading indicator or placeholder to display.', + ); } + + suspended = true; } else { throw err; } @@ -1097,39 +1092,35 @@ class ReactDOMServerRenderer { return ''; } case REACT_SUSPENSE_TYPE: { - if (enableSuspenseServerRenderer) { - const fallback = ((nextChild: any): ReactElement).props.fallback; - const fallbackChildren = toArray(fallback); - const nextChildren = toArray( - ((nextChild: any): ReactElement).props.children, - ); - const fallbackFrame: Frame = { - type: null, - domNamespace: parentNamespace, - children: fallbackChildren, - childIndex: 0, - context: context, - footer: '', - }; - const frame: Frame = { - fallbackFrame, - type: REACT_SUSPENSE_TYPE, - domNamespace: parentNamespace, - children: nextChildren, - childIndex: 0, - context: context, - footer: '', - }; - if (__DEV__) { - ((frame: any): FrameDev).debugElementStack = []; - ((fallbackFrame: any): FrameDev).debugElementStack = []; - } - this.stack.push(frame); - this.suspenseDepth++; - return ''; - } else { - throw new Error('ReactDOMServer does not yet support Suspense.'); + const fallback = ((nextChild: any): ReactElement).props.fallback; + const fallbackChildren = toArray(fallback); + const nextChildren = toArray( + ((nextChild: any): ReactElement).props.children, + ); + const fallbackFrame: Frame = { + type: null, + domNamespace: parentNamespace, + children: fallbackChildren, + childIndex: 0, + context: context, + footer: '', + }; + const frame: Frame = { + fallbackFrame, + type: REACT_SUSPENSE_TYPE, + domNamespace: parentNamespace, + children: nextChildren, + childIndex: 0, + context: context, + footer: '', + }; + if (__DEV__) { + ((frame: any): FrameDev).debugElementStack = []; + ((fallbackFrame: any): FrameDev).debugElementStack = []; } + this.stack.push(frame); + this.suspenseDepth++; + return ''; } // eslint-disable-next-line-no-fallthrough case REACT_SCOPE_TYPE: { diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.new.js b/packages/react-reconciler/src/ReactFiberBeginWork.new.js index 88876f05f7d8d..442c95b651250 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.new.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.new.js @@ -96,7 +96,6 @@ import { disableModulePatternComponents, enableProfilerCommitHooks, enableProfilerTimer, - enableSuspenseServerRenderer, warnAboutDefaultPropsOnFunctionComponents, enableScopeAPI, enableCache, @@ -2134,17 +2133,15 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) { // If we're currently hydrating, try to hydrate this boundary. tryToClaimNextHydratableInstance(workInProgress); // This could've been a dehydrated suspense component. - if (enableSuspenseServerRenderer) { - const suspenseState: null | SuspenseState = workInProgress.memoizedState; - if (suspenseState !== null) { - const dehydrated = suspenseState.dehydrated; - if (dehydrated !== null) { - return mountDehydratedSuspenseComponent( - workInProgress, - dehydrated, - renderLanes, - ); - } + const suspenseState: null | SuspenseState = workInProgress.memoizedState; + if (suspenseState !== null) { + const dehydrated = suspenseState.dehydrated; + if (dehydrated !== null) { + return mountDehydratedSuspenseComponent( + workInProgress, + dehydrated, + renderLanes, + ); } } @@ -2220,59 +2217,57 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) { // The current tree is already showing a fallback // Special path for hydration - if (enableSuspenseServerRenderer) { - const dehydrated = prevState.dehydrated; - if (dehydrated !== null) { - if (!didSuspend) { - return updateDehydratedSuspenseComponent( - current, - workInProgress, - dehydrated, - prevState, - renderLanes, - ); - } else if (workInProgress.flags & ForceClientRender) { - // Something errored during hydration. Try again without hydrating. - workInProgress.flags &= ~ForceClientRender; - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - new Error( - 'There was an error while hydrating this Suspense boundary. ' + - 'Switched to client rendering.', - ), - ); - } else if ( - (workInProgress.memoizedState: null | SuspenseState) !== null - ) { - // Something suspended and we should still be in dehydrated mode. - // Leave the existing child in place. - workInProgress.child = current.child; - // The dehydrated completion pass expects this flag to be there - // but the normal suspense pass doesn't. - workInProgress.flags |= DidCapture; - return null; - } else { - // Suspended but we should no longer be in dehydrated mode. - // Therefore we now have to render the fallback. - renderDidSuspendDelayIfPossible(); - const nextPrimaryChildren = nextProps.children; - const nextFallbackChildren = nextProps.fallback; - const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating( - current, - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes, - ); - const primaryChildFragment: Fiber = (workInProgress.child: any); - primaryChildFragment.memoizedState = mountSuspenseOffscreenState( - renderLanes, - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } + const dehydrated = prevState.dehydrated; + if (dehydrated !== null) { + if (!didSuspend) { + return updateDehydratedSuspenseComponent( + current, + workInProgress, + dehydrated, + prevState, + renderLanes, + ); + } else if (workInProgress.flags & ForceClientRender) { + // Something errored during hydration. Try again without hydrating. + workInProgress.flags &= ~ForceClientRender; + return retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + new Error( + 'There was an error while hydrating this Suspense boundary. ' + + 'Switched to client rendering.', + ), + ); + } else if ( + (workInProgress.memoizedState: null | SuspenseState) !== null + ) { + // Something suspended and we should still be in dehydrated mode. + // Leave the existing child in place. + workInProgress.child = current.child; + // The dehydrated completion pass expects this flag to be there + // but the normal suspense pass doesn't. + workInProgress.flags |= DidCapture; + return null; + } else { + // Suspended but we should no longer be in dehydrated mode. + // Therefore we now have to render the fallback. + renderDidSuspendDelayIfPossible(); + const nextPrimaryChildren = nextProps.children; + const nextFallbackChildren = nextProps.fallback; + const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating( + current, + workInProgress, + nextPrimaryChildren, + nextFallbackChildren, + renderLanes, + ); + const primaryChildFragment: Fiber = (workInProgress.child: any); + primaryChildFragment.memoizedState = mountSuspenseOffscreenState( + renderLanes, + ); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; } } @@ -3657,20 +3652,18 @@ function attemptEarlyBailoutIfNoScheduledUpdate( case SuspenseComponent: { const state: SuspenseState | null = workInProgress.memoizedState; if (state !== null) { - if (enableSuspenseServerRenderer) { - if (state.dehydrated !== null) { - pushSuspenseContext( - workInProgress, - setDefaultShallowSuspenseContext(suspenseStackCursor.current), - ); - // We know that this component will suspend again because if it has - // been unsuspended it has committed as a resolved Suspense component. - // If it needs to be retried, it should have work scheduled on it. - workInProgress.flags |= DidCapture; - // We should never render the children of a dehydrated boundary until we - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. - return null; - } + if (state.dehydrated !== null) { + pushSuspenseContext( + workInProgress, + setDefaultShallowSuspenseContext(suspenseStackCursor.current), + ); + // We know that this component will suspend again because if it has + // been unsuspended it has committed as a resolved Suspense component. + // If it needs to be retried, it should have work scheduled on it. + workInProgress.flags |= DidCapture; + // We should never render the children of a dehydrated boundary until we + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. + return null; } // If this boundary is currently timed out, we need to decide diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.old.js b/packages/react-reconciler/src/ReactFiberBeginWork.old.js index 418b714117e81..1632501b26db2 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.old.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.old.js @@ -96,7 +96,6 @@ import { disableModulePatternComponents, enableProfilerCommitHooks, enableProfilerTimer, - enableSuspenseServerRenderer, warnAboutDefaultPropsOnFunctionComponents, enableScopeAPI, enableCache, @@ -2134,17 +2133,15 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) { // If we're currently hydrating, try to hydrate this boundary. tryToClaimNextHydratableInstance(workInProgress); // This could've been a dehydrated suspense component. - if (enableSuspenseServerRenderer) { - const suspenseState: null | SuspenseState = workInProgress.memoizedState; - if (suspenseState !== null) { - const dehydrated = suspenseState.dehydrated; - if (dehydrated !== null) { - return mountDehydratedSuspenseComponent( - workInProgress, - dehydrated, - renderLanes, - ); - } + const suspenseState: null | SuspenseState = workInProgress.memoizedState; + if (suspenseState !== null) { + const dehydrated = suspenseState.dehydrated; + if (dehydrated !== null) { + return mountDehydratedSuspenseComponent( + workInProgress, + dehydrated, + renderLanes, + ); } } @@ -2220,59 +2217,57 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) { // The current tree is already showing a fallback // Special path for hydration - if (enableSuspenseServerRenderer) { - const dehydrated = prevState.dehydrated; - if (dehydrated !== null) { - if (!didSuspend) { - return updateDehydratedSuspenseComponent( - current, - workInProgress, - dehydrated, - prevState, - renderLanes, - ); - } else if (workInProgress.flags & ForceClientRender) { - // Something errored during hydration. Try again without hydrating. - workInProgress.flags &= ~ForceClientRender; - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - new Error( - 'There was an error while hydrating this Suspense boundary. ' + - 'Switched to client rendering.', - ), - ); - } else if ( - (workInProgress.memoizedState: null | SuspenseState) !== null - ) { - // Something suspended and we should still be in dehydrated mode. - // Leave the existing child in place. - workInProgress.child = current.child; - // The dehydrated completion pass expects this flag to be there - // but the normal suspense pass doesn't. - workInProgress.flags |= DidCapture; - return null; - } else { - // Suspended but we should no longer be in dehydrated mode. - // Therefore we now have to render the fallback. - renderDidSuspendDelayIfPossible(); - const nextPrimaryChildren = nextProps.children; - const nextFallbackChildren = nextProps.fallback; - const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating( - current, - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes, - ); - const primaryChildFragment: Fiber = (workInProgress.child: any); - primaryChildFragment.memoizedState = mountSuspenseOffscreenState( - renderLanes, - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } + const dehydrated = prevState.dehydrated; + if (dehydrated !== null) { + if (!didSuspend) { + return updateDehydratedSuspenseComponent( + current, + workInProgress, + dehydrated, + prevState, + renderLanes, + ); + } else if (workInProgress.flags & ForceClientRender) { + // Something errored during hydration. Try again without hydrating. + workInProgress.flags &= ~ForceClientRender; + return retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + new Error( + 'There was an error while hydrating this Suspense boundary. ' + + 'Switched to client rendering.', + ), + ); + } else if ( + (workInProgress.memoizedState: null | SuspenseState) !== null + ) { + // Something suspended and we should still be in dehydrated mode. + // Leave the existing child in place. + workInProgress.child = current.child; + // The dehydrated completion pass expects this flag to be there + // but the normal suspense pass doesn't. + workInProgress.flags |= DidCapture; + return null; + } else { + // Suspended but we should no longer be in dehydrated mode. + // Therefore we now have to render the fallback. + renderDidSuspendDelayIfPossible(); + const nextPrimaryChildren = nextProps.children; + const nextFallbackChildren = nextProps.fallback; + const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating( + current, + workInProgress, + nextPrimaryChildren, + nextFallbackChildren, + renderLanes, + ); + const primaryChildFragment: Fiber = (workInProgress.child: any); + primaryChildFragment.memoizedState = mountSuspenseOffscreenState( + renderLanes, + ); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; } } @@ -3657,20 +3652,18 @@ function attemptEarlyBailoutIfNoScheduledUpdate( case SuspenseComponent: { const state: SuspenseState | null = workInProgress.memoizedState; if (state !== null) { - if (enableSuspenseServerRenderer) { - if (state.dehydrated !== null) { - pushSuspenseContext( - workInProgress, - setDefaultShallowSuspenseContext(suspenseStackCursor.current), - ); - // We know that this component will suspend again because if it has - // been unsuspended it has committed as a resolved Suspense component. - // If it needs to be retried, it should have work scheduled on it. - workInProgress.flags |= DidCapture; - // We should never render the children of a dehydrated boundary until we - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. - return null; - } + if (state.dehydrated !== null) { + pushSuspenseContext( + workInProgress, + setDefaultShallowSuspenseContext(suspenseStackCursor.current), + ); + // We know that this component will suspend again because if it has + // been unsuspended it has committed as a resolved Suspense component. + // If it needs to be retried, it should have work scheduled on it. + workInProgress.flags |= DidCapture; + // We should never render the children of a dehydrated boundary until we + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. + return null; } // If this boundary is currently timed out, we need to decide diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 2cb02b2a54664..6712e27bd28e1 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -34,7 +34,6 @@ import { enableProfilerCommitHooks, enableProfilerNestedUpdatePhase, enableSchedulingProfiler, - enableSuspenseServerRenderer, enableSuspenseCallback, enableScopeAPI, enableStrictEffects, @@ -1652,33 +1651,31 @@ function commitDeletionEffectsOnFiber( return; } case DehydratedFragment: { - if (enableSuspenseServerRenderer) { - if (enableSuspenseCallback) { - const hydrationCallbacks = finishedRoot.hydrationCallbacks; - if (hydrationCallbacks !== null) { - const onDeleted = hydrationCallbacks.onDeleted; - if (onDeleted) { - onDeleted((deletedFiber.stateNode: SuspenseInstance)); - } + if (enableSuspenseCallback) { + const hydrationCallbacks = finishedRoot.hydrationCallbacks; + if (hydrationCallbacks !== null) { + const onDeleted = hydrationCallbacks.onDeleted; + if (onDeleted) { + onDeleted((deletedFiber.stateNode: SuspenseInstance)); } } + } - // Dehydrated fragments don't have any children + // Dehydrated fragments don't have any children - // Delete the dehydrated suspense boundary and all of its content. - if (supportsMutation) { - if (hostParent !== null) { - if (hostParentIsContainer) { - clearSuspenseBoundaryFromContainer( - ((hostParent: any): Container), - (deletedFiber.stateNode: SuspenseInstance), - ); - } else { - clearSuspenseBoundary( - ((hostParent: any): Instance), - (deletedFiber.stateNode: SuspenseInstance), - ); - } + // Delete the dehydrated suspense boundary and all of its content. + if (supportsMutation) { + if (hostParent !== null) { + if (hostParentIsContainer) { + clearSuspenseBoundaryFromContainer( + ((hostParent: any): Container), + (deletedFiber.stateNode: SuspenseInstance), + ); + } else { + clearSuspenseBoundary( + ((hostParent: any): Instance), + (deletedFiber.stateNode: SuspenseInstance), + ); } } } diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index fbd3873fa54fa..a00355b6f5fc8 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -34,7 +34,6 @@ import { enableProfilerCommitHooks, enableProfilerNestedUpdatePhase, enableSchedulingProfiler, - enableSuspenseServerRenderer, enableSuspenseCallback, enableScopeAPI, enableStrictEffects, @@ -1652,33 +1651,31 @@ function commitDeletionEffectsOnFiber( return; } case DehydratedFragment: { - if (enableSuspenseServerRenderer) { - if (enableSuspenseCallback) { - const hydrationCallbacks = finishedRoot.hydrationCallbacks; - if (hydrationCallbacks !== null) { - const onDeleted = hydrationCallbacks.onDeleted; - if (onDeleted) { - onDeleted((deletedFiber.stateNode: SuspenseInstance)); - } + if (enableSuspenseCallback) { + const hydrationCallbacks = finishedRoot.hydrationCallbacks; + if (hydrationCallbacks !== null) { + const onDeleted = hydrationCallbacks.onDeleted; + if (onDeleted) { + onDeleted((deletedFiber.stateNode: SuspenseInstance)); } } + } - // Dehydrated fragments don't have any children + // Dehydrated fragments don't have any children - // Delete the dehydrated suspense boundary and all of its content. - if (supportsMutation) { - if (hostParent !== null) { - if (hostParentIsContainer) { - clearSuspenseBoundaryFromContainer( - ((hostParent: any): Container), - (deletedFiber.stateNode: SuspenseInstance), - ); - } else { - clearSuspenseBoundary( - ((hostParent: any): Instance), - (deletedFiber.stateNode: SuspenseInstance), - ); - } + // Delete the dehydrated suspense boundary and all of its content. + if (supportsMutation) { + if (hostParent !== null) { + if (hostParentIsContainer) { + clearSuspenseBoundaryFromContainer( + ((hostParent: any): Container), + (deletedFiber.stateNode: SuspenseInstance), + ); + } else { + clearSuspenseBoundary( + ((hostParent: any): Instance), + (deletedFiber.stateNode: SuspenseInstance), + ); } } } diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js index 6beb7eadce375..683d29ab3c880 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js @@ -138,7 +138,6 @@ import { } from './ReactFiberHydrationContext.new'; import { enableSuspenseCallback, - enableSuspenseServerRenderer, enableScopeAPI, enableProfilerTimer, enableCache, @@ -1066,85 +1065,82 @@ function completeWork( popSuspenseContext(workInProgress); const nextState: null | SuspenseState = workInProgress.memoizedState; - if (enableSuspenseServerRenderer) { - if ( - enableClientRenderFallbackOnHydrationMismatch && - hasUnhydratedTailNodes() && - (workInProgress.mode & ConcurrentMode) !== NoMode && - (workInProgress.flags & DidCapture) === NoFlags - ) { - warnIfUnhydratedTailNodes(workInProgress); - resetHydrationState(); - workInProgress.flags |= - ForceClientRender | Incomplete | ShouldCapture; - return workInProgress; - } - if (nextState !== null && nextState.dehydrated !== null) { - // We might be inside a hydration state the first time we're picking up this - // Suspense boundary, and also after we've reentered it for further hydration. - const wasHydrated = popHydrationState(workInProgress); - if (current === null) { - if (!wasHydrated) { - throw new Error( - 'A dehydrated suspense component was completed without a hydrated node. ' + - 'This is probably a bug in React.', - ); - } - prepareToHydrateHostSuspenseInstance(workInProgress); - bubbleProperties(workInProgress); - if (enableProfilerTimer) { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - const isTimedOutSuspense = nextState !== null; - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - const primaryChildFragment = workInProgress.child; - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); - } + if ( + enableClientRenderFallbackOnHydrationMismatch && + hasUnhydratedTailNodes() && + (workInProgress.mode & ConcurrentMode) !== NoMode && + (workInProgress.flags & DidCapture) === NoFlags + ) { + warnIfUnhydratedTailNodes(workInProgress); + resetHydrationState(); + workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture; + return workInProgress; + } + if (nextState !== null && nextState.dehydrated !== null) { + // We might be inside a hydration state the first time we're picking up this + // Suspense boundary, and also after we've reentered it for further hydration. + const wasHydrated = popHydrationState(workInProgress); + if (current === null) { + if (!wasHydrated) { + throw new Error( + 'A dehydrated suspense component was completed without a hydrated node. ' + + 'This is probably a bug in React.', + ); + } + prepareToHydrateHostSuspenseInstance(workInProgress); + bubbleProperties(workInProgress); + if (enableProfilerTimer) { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + const isTimedOutSuspense = nextState !== null; + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + const primaryChildFragment = workInProgress.child; + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); } } } - return null; - } else { - // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration - // state since we're now exiting out of it. popHydrationState doesn't do that for us. - resetHydrationState(); - if ((workInProgress.flags & DidCapture) === NoFlags) { - // This boundary did not suspend so it's now hydrated and unsuspended. - workInProgress.memoizedState = null; - } - // If nothing suspended, we need to schedule an effect to mark this boundary - // as having hydrated so events know that they're free to be invoked. - // It's also a signal to replay events and the suspense callback. - // If something suspended, schedule an effect to attach retry listeners. - // So we might as well always mark this. - workInProgress.flags |= Update; - bubbleProperties(workInProgress); - if (enableProfilerTimer) { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - const isTimedOutSuspense = nextState !== null; - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - const primaryChildFragment = workInProgress.child; - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); - } + } + return null; + } else { + // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration + // state since we're now exiting out of it. popHydrationState doesn't do that for us. + resetHydrationState(); + if ((workInProgress.flags & DidCapture) === NoFlags) { + // This boundary did not suspend so it's now hydrated and unsuspended. + workInProgress.memoizedState = null; + } + // If nothing suspended, we need to schedule an effect to mark this boundary + // as having hydrated so events know that they're free to be invoked. + // It's also a signal to replay events and the suspense callback. + // If something suspended, schedule an effect to attach retry listeners. + // So we might as well always mark this. + workInProgress.flags |= Update; + bubbleProperties(workInProgress); + if (enableProfilerTimer) { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + const isTimedOutSuspense = nextState !== null; + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + const primaryChildFragment = workInProgress.child; + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); } } } - return null; } + return null; } - - // Successfully completed this tree. If this was a forced client render, - // there may have been recoverable errors during first hydration - // attempt. If so, add them to a queue so we can log them in the - // commit phase. - upgradeHydrationErrorsToRecoverable(); } + // Successfully completed this tree. If this was a forced client render, + // there may have been recoverable errors during first hydration + // attempt. If so, add them to a queue so we can log them in the + // commit phase. + upgradeHydrationErrorsToRecoverable(); + if ((workInProgress.flags & DidCapture) !== NoFlags) { // Something suspended. Re-render with the fallback children. workInProgress.lanes = renderLanes; diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js index fc9414efc2796..549e3da16b035 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js @@ -138,7 +138,6 @@ import { } from './ReactFiberHydrationContext.old'; import { enableSuspenseCallback, - enableSuspenseServerRenderer, enableScopeAPI, enableProfilerTimer, enableCache, @@ -1066,85 +1065,82 @@ function completeWork( popSuspenseContext(workInProgress); const nextState: null | SuspenseState = workInProgress.memoizedState; - if (enableSuspenseServerRenderer) { - if ( - enableClientRenderFallbackOnHydrationMismatch && - hasUnhydratedTailNodes() && - (workInProgress.mode & ConcurrentMode) !== NoMode && - (workInProgress.flags & DidCapture) === NoFlags - ) { - warnIfUnhydratedTailNodes(workInProgress); - resetHydrationState(); - workInProgress.flags |= - ForceClientRender | Incomplete | ShouldCapture; - return workInProgress; - } - if (nextState !== null && nextState.dehydrated !== null) { - // We might be inside a hydration state the first time we're picking up this - // Suspense boundary, and also after we've reentered it for further hydration. - const wasHydrated = popHydrationState(workInProgress); - if (current === null) { - if (!wasHydrated) { - throw new Error( - 'A dehydrated suspense component was completed without a hydrated node. ' + - 'This is probably a bug in React.', - ); - } - prepareToHydrateHostSuspenseInstance(workInProgress); - bubbleProperties(workInProgress); - if (enableProfilerTimer) { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - const isTimedOutSuspense = nextState !== null; - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - const primaryChildFragment = workInProgress.child; - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); - } + if ( + enableClientRenderFallbackOnHydrationMismatch && + hasUnhydratedTailNodes() && + (workInProgress.mode & ConcurrentMode) !== NoMode && + (workInProgress.flags & DidCapture) === NoFlags + ) { + warnIfUnhydratedTailNodes(workInProgress); + resetHydrationState(); + workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture; + return workInProgress; + } + if (nextState !== null && nextState.dehydrated !== null) { + // We might be inside a hydration state the first time we're picking up this + // Suspense boundary, and also after we've reentered it for further hydration. + const wasHydrated = popHydrationState(workInProgress); + if (current === null) { + if (!wasHydrated) { + throw new Error( + 'A dehydrated suspense component was completed without a hydrated node. ' + + 'This is probably a bug in React.', + ); + } + prepareToHydrateHostSuspenseInstance(workInProgress); + bubbleProperties(workInProgress); + if (enableProfilerTimer) { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + const isTimedOutSuspense = nextState !== null; + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + const primaryChildFragment = workInProgress.child; + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); } } } - return null; - } else { - // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration - // state since we're now exiting out of it. popHydrationState doesn't do that for us. - resetHydrationState(); - if ((workInProgress.flags & DidCapture) === NoFlags) { - // This boundary did not suspend so it's now hydrated and unsuspended. - workInProgress.memoizedState = null; - } - // If nothing suspended, we need to schedule an effect to mark this boundary - // as having hydrated so events know that they're free to be invoked. - // It's also a signal to replay events and the suspense callback. - // If something suspended, schedule an effect to attach retry listeners. - // So we might as well always mark this. - workInProgress.flags |= Update; - bubbleProperties(workInProgress); - if (enableProfilerTimer) { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - const isTimedOutSuspense = nextState !== null; - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - const primaryChildFragment = workInProgress.child; - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); - } + } + return null; + } else { + // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration + // state since we're now exiting out of it. popHydrationState doesn't do that for us. + resetHydrationState(); + if ((workInProgress.flags & DidCapture) === NoFlags) { + // This boundary did not suspend so it's now hydrated and unsuspended. + workInProgress.memoizedState = null; + } + // If nothing suspended, we need to schedule an effect to mark this boundary + // as having hydrated so events know that they're free to be invoked. + // It's also a signal to replay events and the suspense callback. + // If something suspended, schedule an effect to attach retry listeners. + // So we might as well always mark this. + workInProgress.flags |= Update; + bubbleProperties(workInProgress); + if (enableProfilerTimer) { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + const isTimedOutSuspense = nextState !== null; + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + const primaryChildFragment = workInProgress.child; + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number); } } } - return null; } + return null; } - - // Successfully completed this tree. If this was a forced client render, - // there may have been recoverable errors during first hydration - // attempt. If so, add them to a queue so we can log them in the - // commit phase. - upgradeHydrationErrorsToRecoverable(); } + // Successfully completed this tree. If this was a forced client render, + // there may have been recoverable errors during first hydration + // attempt. If so, add them to a queue so we can log them in the + // commit phase. + upgradeHydrationErrorsToRecoverable(); + if ((workInProgress.flags & DidCapture) !== NoFlags) { // Something suspended. Re-render with the fallback children. workInProgress.lanes = renderLanes; diff --git a/packages/react-reconciler/src/ReactFiberHydrationContext.new.js b/packages/react-reconciler/src/ReactFiberHydrationContext.new.js index 94ca9e61eec15..98981e904a90a 100644 --- a/packages/react-reconciler/src/ReactFiberHydrationContext.new.js +++ b/packages/react-reconciler/src/ReactFiberHydrationContext.new.js @@ -68,10 +68,7 @@ import { didNotFindHydratableTextInstance, didNotFindHydratableSuspenseInstance, } from './ReactFiberHostConfig'; -import { - enableClientRenderFallbackOnHydrationMismatch, - enableSuspenseServerRenderer, -} from 'shared/ReactFeatureFlags'; +import {enableClientRenderFallbackOnHydrationMismatch} from 'shared/ReactFeatureFlags'; import {OffscreenLane} from './ReactFiberLane.new'; import { getSuspendedTreeContext, @@ -347,32 +344,30 @@ function tryHydrate(fiber, nextInstance) { return false; } case SuspenseComponent: { - if (enableSuspenseServerRenderer) { - const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance( - nextInstance, + const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance( + nextInstance, + ); + if (suspenseInstance !== null) { + const suspenseState: SuspenseState = { + dehydrated: suspenseInstance, + treeContext: getSuspendedTreeContext(), + retryLane: OffscreenLane, + }; + fiber.memoizedState = suspenseState; + // Store the dehydrated fragment as a child fiber. + // This simplifies the code for getHostSibling and deleting nodes, + // since it doesn't have to consider all Suspense boundaries and + // check if they're dehydrated ones or not. + const dehydratedFragment = createFiberFromDehydratedFragment( + suspenseInstance, ); - if (suspenseInstance !== null) { - const suspenseState: SuspenseState = { - dehydrated: suspenseInstance, - treeContext: getSuspendedTreeContext(), - retryLane: OffscreenLane, - }; - fiber.memoizedState = suspenseState; - // Store the dehydrated fragment as a child fiber. - // This simplifies the code for getHostSibling and deleting nodes, - // since it doesn't have to consider all Suspense boundaries and - // check if they're dehydrated ones or not. - const dehydratedFragment = createFiberFromDehydratedFragment( - suspenseInstance, - ); - dehydratedFragment.return = fiber; - fiber.child = dehydratedFragment; - hydrationParentFiber = fiber; - // While a Suspense Instance does have children, we won't step into - // it during the first pass. Instead, we'll reenter it later. - nextHydratableInstance = null; - return true; - } + dehydratedFragment.return = fiber; + fiber.child = dehydratedFragment; + hydrationParentFiber = fiber; + // While a Suspense Instance does have children, we won't step into + // it during the first pass. Instead, we'll reenter it later. + nextHydratableInstance = null; + return true; } return false; } diff --git a/packages/react-reconciler/src/ReactFiberHydrationContext.old.js b/packages/react-reconciler/src/ReactFiberHydrationContext.old.js index 6af68fe66a79d..fd98256927847 100644 --- a/packages/react-reconciler/src/ReactFiberHydrationContext.old.js +++ b/packages/react-reconciler/src/ReactFiberHydrationContext.old.js @@ -68,10 +68,7 @@ import { didNotFindHydratableTextInstance, didNotFindHydratableSuspenseInstance, } from './ReactFiberHostConfig'; -import { - enableClientRenderFallbackOnHydrationMismatch, - enableSuspenseServerRenderer, -} from 'shared/ReactFeatureFlags'; +import {enableClientRenderFallbackOnHydrationMismatch} from 'shared/ReactFeatureFlags'; import {OffscreenLane} from './ReactFiberLane.old'; import { getSuspendedTreeContext, @@ -347,32 +344,30 @@ function tryHydrate(fiber, nextInstance) { return false; } case SuspenseComponent: { - if (enableSuspenseServerRenderer) { - const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance( - nextInstance, + const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance( + nextInstance, + ); + if (suspenseInstance !== null) { + const suspenseState: SuspenseState = { + dehydrated: suspenseInstance, + treeContext: getSuspendedTreeContext(), + retryLane: OffscreenLane, + }; + fiber.memoizedState = suspenseState; + // Store the dehydrated fragment as a child fiber. + // This simplifies the code for getHostSibling and deleting nodes, + // since it doesn't have to consider all Suspense boundaries and + // check if they're dehydrated ones or not. + const dehydratedFragment = createFiberFromDehydratedFragment( + suspenseInstance, ); - if (suspenseInstance !== null) { - const suspenseState: SuspenseState = { - dehydrated: suspenseInstance, - treeContext: getSuspendedTreeContext(), - retryLane: OffscreenLane, - }; - fiber.memoizedState = suspenseState; - // Store the dehydrated fragment as a child fiber. - // This simplifies the code for getHostSibling and deleting nodes, - // since it doesn't have to consider all Suspense boundaries and - // check if they're dehydrated ones or not. - const dehydratedFragment = createFiberFromDehydratedFragment( - suspenseInstance, - ); - dehydratedFragment.return = fiber; - fiber.child = dehydratedFragment; - hydrationParentFiber = fiber; - // While a Suspense Instance does have children, we won't step into - // it during the first pass. Instead, we'll reenter it later. - nextHydratableInstance = null; - return true; - } + dehydratedFragment.return = fiber; + fiber.child = dehydratedFragment; + hydrationParentFiber = fiber; + // While a Suspense Instance does have children, we won't step into + // it during the first pass. Instead, we'll reenter it later. + nextHydratableInstance = null; + return true; } return false; } diff --git a/packages/react-reconciler/src/ReactFiberNewContext.new.js b/packages/react-reconciler/src/ReactFiberNewContext.new.js index 8f269a4050215..68862e568818f 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.new.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.new.js @@ -42,7 +42,6 @@ import is from 'shared/objectIs'; import {createUpdate, ForceUpdate} from './ReactUpdateQueue.new'; import {markWorkInProgressReceivedUpdate} from './ReactFiberBeginWork.new'; import { - enableSuspenseServerRenderer, enableLazyContextPropagation, enableServerContext, } from 'shared/ReactFeatureFlags'; @@ -295,10 +294,7 @@ function propagateContextChange_eager( } else if (fiber.tag === ContextProvider) { // Don't scan deeper if this is a matching provider nextFiber = fiber.type === workInProgress.type ? null : fiber.child; - } else if ( - enableSuspenseServerRenderer && - fiber.tag === DehydratedFragment - ) { + } else if (fiber.tag === DehydratedFragment) { // If a dehydrated suspense boundary is in this subtree, we don't know // if it will have any context consumers in it. The best we can do is // mark it as having updates. @@ -425,10 +421,7 @@ function propagateContextChanges( } dep = dependency.next; } - } else if ( - enableSuspenseServerRenderer && - fiber.tag === DehydratedFragment - ) { + } else if (fiber.tag === DehydratedFragment) { // If a dehydrated suspense boundary is in this subtree, we don't know // if it will have any context consumers in it. The best we can do is // mark it as having updates. diff --git a/packages/react-reconciler/src/ReactFiberNewContext.old.js b/packages/react-reconciler/src/ReactFiberNewContext.old.js index a48c842043821..de96664e774a2 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.old.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.old.js @@ -42,7 +42,6 @@ import is from 'shared/objectIs'; import {createUpdate, ForceUpdate} from './ReactUpdateQueue.old'; import {markWorkInProgressReceivedUpdate} from './ReactFiberBeginWork.old'; import { - enableSuspenseServerRenderer, enableLazyContextPropagation, enableServerContext, } from 'shared/ReactFeatureFlags'; @@ -295,10 +294,7 @@ function propagateContextChange_eager( } else if (fiber.tag === ContextProvider) { // Don't scan deeper if this is a matching provider nextFiber = fiber.type === workInProgress.type ? null : fiber.child; - } else if ( - enableSuspenseServerRenderer && - fiber.tag === DehydratedFragment - ) { + } else if (fiber.tag === DehydratedFragment) { // If a dehydrated suspense boundary is in this subtree, we don't know // if it will have any context consumers in it. The best we can do is // mark it as having updates. @@ -425,10 +421,7 @@ function propagateContextChanges( } dep = dependency.next; } - } else if ( - enableSuspenseServerRenderer && - fiber.tag === DehydratedFragment - ) { + } else if (fiber.tag === DehydratedFragment) { // If a dehydrated suspense boundary is in this subtree, we don't know // if it will have any context consumers in it. The best we can do is // mark it as having updates. diff --git a/packages/react-reconciler/src/ReactFiberUnwindWork.new.js b/packages/react-reconciler/src/ReactFiberUnwindWork.new.js index eb2ea2286a275..c97c3e2ebc166 100644 --- a/packages/react-reconciler/src/ReactFiberUnwindWork.new.js +++ b/packages/react-reconciler/src/ReactFiberUnwindWork.new.js @@ -28,11 +28,7 @@ import { } from './ReactWorkTags'; import {DidCapture, NoFlags, ShouldCapture} from './ReactFiberFlags'; import {NoMode, ProfileMode} from './ReactTypeOfMode'; -import { - enableSuspenseServerRenderer, - enableProfilerTimer, - enableCache, -} from 'shared/ReactFeatureFlags'; +import {enableProfilerTimer, enableCache} from 'shared/ReactFeatureFlags'; import {popHostContainer, popHostContext} from './ReactFiberHostContext.new'; import {popSuspenseContext} from './ReactFiberSuspenseContext.new'; @@ -108,20 +104,18 @@ function unwindWork( } case SuspenseComponent: { popSuspenseContext(workInProgress); - if (enableSuspenseServerRenderer) { - const suspenseState: null | SuspenseState = - workInProgress.memoizedState; - if (suspenseState !== null && suspenseState.dehydrated !== null) { - if (workInProgress.alternate === null) { - throw new Error( - 'Threw in newly mounted dehydrated component. This is likely a bug in ' + - 'React. Please file an issue.', - ); - } - - resetHydrationState(); + const suspenseState: null | SuspenseState = workInProgress.memoizedState; + if (suspenseState !== null && suspenseState.dehydrated !== null) { + if (workInProgress.alternate === null) { + throw new Error( + 'Threw in newly mounted dehydrated component. This is likely a bug in ' + + 'React. Please file an issue.', + ); } + + resetHydrationState(); } + const flags = workInProgress.flags; if (flags & ShouldCapture) { workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; diff --git a/packages/react-reconciler/src/ReactFiberUnwindWork.old.js b/packages/react-reconciler/src/ReactFiberUnwindWork.old.js index 1eb4d72d98c98..260b574b264fe 100644 --- a/packages/react-reconciler/src/ReactFiberUnwindWork.old.js +++ b/packages/react-reconciler/src/ReactFiberUnwindWork.old.js @@ -28,11 +28,7 @@ import { } from './ReactWorkTags'; import {DidCapture, NoFlags, ShouldCapture} from './ReactFiberFlags'; import {NoMode, ProfileMode} from './ReactTypeOfMode'; -import { - enableSuspenseServerRenderer, - enableProfilerTimer, - enableCache, -} from 'shared/ReactFeatureFlags'; +import {enableProfilerTimer, enableCache} from 'shared/ReactFeatureFlags'; import {popHostContainer, popHostContext} from './ReactFiberHostContext.old'; import {popSuspenseContext} from './ReactFiberSuspenseContext.old'; @@ -108,20 +104,18 @@ function unwindWork( } case SuspenseComponent: { popSuspenseContext(workInProgress); - if (enableSuspenseServerRenderer) { - const suspenseState: null | SuspenseState = - workInProgress.memoizedState; - if (suspenseState !== null && suspenseState.dehydrated !== null) { - if (workInProgress.alternate === null) { - throw new Error( - 'Threw in newly mounted dehydrated component. This is likely a bug in ' + - 'React. Please file an issue.', - ); - } - - resetHydrationState(); + const suspenseState: null | SuspenseState = workInProgress.memoizedState; + if (suspenseState !== null && suspenseState.dehydrated !== null) { + if (workInProgress.alternate === null) { + throw new Error( + 'Threw in newly mounted dehydrated component. This is likely a bug in ' + + 'React. Please file an issue.', + ); } + + resetHydrationState(); } + const flags = workInProgress.flags; if (flags & ShouldCapture) { workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index e9381e709f226..aa20335cbec91 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -23,7 +23,6 @@ import type { import { warnAboutDeprecatedLifecycles, - enableSuspenseServerRenderer, replayFailedUnitOfWorkWithInvokeGuardedCallback, enableCreateEventHandleAPI, enableProfilerTimer, @@ -2776,26 +2775,22 @@ export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) { export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) { let retryLane = NoLane; // Default let retryCache: WeakSet | Set | null; - if (enableSuspenseServerRenderer) { - switch (boundaryFiber.tag) { - case SuspenseComponent: - retryCache = boundaryFiber.stateNode; - const suspenseState: null | SuspenseState = boundaryFiber.memoizedState; - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } - break; - case SuspenseListComponent: - retryCache = boundaryFiber.stateNode; - break; - default: - throw new Error( - 'Pinged unknown suspense boundary type. ' + - 'This is probably a bug in React.', - ); - } - } else { - retryCache = boundaryFiber.stateNode; + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + const suspenseState: null | SuspenseState = boundaryFiber.memoizedState; + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } + break; + case SuspenseListComponent: + retryCache = boundaryFiber.stateNode; + break; + default: + throw new Error( + 'Pinged unknown suspense boundary type. ' + + 'This is probably a bug in React.', + ); } if (retryCache !== null) { diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js index 5d25610f5f4a8..e2c3a76c7fc24 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js @@ -23,7 +23,6 @@ import type { import { warnAboutDeprecatedLifecycles, - enableSuspenseServerRenderer, replayFailedUnitOfWorkWithInvokeGuardedCallback, enableCreateEventHandleAPI, enableProfilerTimer, @@ -2776,26 +2775,22 @@ export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) { export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) { let retryLane = NoLane; // Default let retryCache: WeakSet | Set | null; - if (enableSuspenseServerRenderer) { - switch (boundaryFiber.tag) { - case SuspenseComponent: - retryCache = boundaryFiber.stateNode; - const suspenseState: null | SuspenseState = boundaryFiber.memoizedState; - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } - break; - case SuspenseListComponent: - retryCache = boundaryFiber.stateNode; - break; - default: - throw new Error( - 'Pinged unknown suspense boundary type. ' + - 'This is probably a bug in React.', - ); - } - } else { - retryCache = boundaryFiber.stateNode; + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + const suspenseState: null | SuspenseState = boundaryFiber.memoizedState; + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } + break; + case SuspenseListComponent: + retryCache = boundaryFiber.stateNode; + break; + default: + throw new Error( + 'Pinged unknown suspense boundary type. ' + + 'This is probably a bug in React.', + ); } if (retryCache !== null) { diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index f7529132aef71..c2a128741d996 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -13,7 +13,6 @@ // Flags that can likely be deleted or landed without consequences // ----------------------------------------------------------------------------- -export const enableSuspenseServerRenderer = true; export const enableSelectiveHydration = true; export const warnAboutDeprecatedLifecycles = true; export const enableComponentStackLocations = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 91795dca3093d..a70d239582938 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -26,7 +26,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerNestedUpdateScheduledHook = false; export const enableUpdaterTracking = __PROFILE__; -export const enableSuspenseServerRenderer = false; export const enableSelectiveHydration = false; export const enableCache = false; export const enableCacheElement = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 3d816e86143c5..5768925fdd0bb 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerNestedUpdateScheduledHook = false; export const enableUpdaterTracking = __PROFILE__; -export const enableSuspenseServerRenderer = false; export const enableSelectiveHydration = false; export const enableCache = false; export const enableCacheElement = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 1aeb14817ad70..6c5c9ffe65967 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerNestedUpdateScheduledHook = false; export const enableUpdaterTracking = false; -export const enableSuspenseServerRenderer = false; export const enableSelectiveHydration = false; export const enableCache = __EXPERIMENTAL__; export const enableCacheElement = __EXPERIMENTAL__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js index 9c19dc2a47c20..dfc904212e61b 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js @@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerNestedUpdateScheduledHook = false; export const enableUpdaterTracking = false; -export const enableSuspenseServerRenderer = false; export const enableSelectiveHydration = false; export const enableCache = true; export const enableCacheElement = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 75e1df4dc34b3..23228bf8b0ec1 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerNestedUpdateScheduledHook = false; export const enableUpdaterTracking = false; -export const enableSuspenseServerRenderer = false; export const enableSelectiveHydration = false; export const enableCache = true; export const enableCacheElement = true; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.js b/packages/shared/forks/ReactFeatureFlags.testing.js index 262e67017da19..87e9fd0fe7d6b 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.js @@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerNestedUpdateScheduledHook = false; export const enableUpdaterTracking = false; -export const enableSuspenseServerRenderer = false; export const enableSelectiveHydration = false; export const enableCache = __EXPERIMENTAL__; export const enableCacheElement = __EXPERIMENTAL__; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.www.js b/packages/shared/forks/ReactFeatureFlags.testing.www.js index ed97f8e51ebc4..fdb4725c47b4c 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.www.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.www.js @@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = false; export const enableProfilerNestedUpdatePhase = false; export const enableProfilerNestedUpdateScheduledHook = false; export const enableUpdaterTracking = false; -export const enableSuspenseServerRenderer = true; export const enableSelectiveHydration = true; export const enableCache = true; export const enableCacheElement = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 5c64417f0bacf..8e6b57b25b1b1 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -67,7 +67,6 @@ export const disableLegacyContext = __EXPERIMENTAL__; export const warnAboutStringRefs = false; export const warnAboutDefaultPropsOnFunctionComponents = false; export const enableGetInspectorDataForInstanceInProduction = false; -export const enableSuspenseServerRenderer = true; export const enableSelectiveHydration = true; export const enableCache = true;