@samitouri / QOS-React-2 / commits / 392808a1f7

Land enableClientRenderFallbackOnTextMismatch flag (#24405)

This flag is already enabled on all relevant surfaces. We can remove it.

Andrew Clark committed Apr 20, 2022 at 10:21 UTC 392808a1f7fa2909492a742116ba8b549e862d70
26 files changed +473 -605
packages/react-dom/src/__tests__/ReactServerRendering-test.js
-37
@@ -14,8 +14,6 @@ let React;
14 let ReactDOMServer;
15 let PropTypes;
16 let ReactCurrentDispatcher;
17 -const enableSuspenseServerRenderer = require('shared/ReactFeatureFlags')
18 - .enableSuspenseServerRenderer;
17
18 describe('ReactDOMServer', () => {
19 beforeEach(() => {
@@ -678,41 +676,6 @@ describe('ReactDOMServer', () => {
676 expect(markup).toBe('<div></div>');
677 });
678
681 - if (!enableSuspenseServerRenderer) {
682 - it('throws for unsupported types on the server', () => {
683 - expect(() => {
684 - ReactDOMServer.renderToString(<React.Suspense />);
685 - }).toThrow('ReactDOMServer does not yet support Suspense.');
686 -
687 - async function fakeImport(result) {
688 - return {default: result};
689 - }
690 -
691 - expect(() => {
692 - const LazyFoo = React.lazy(() =>
693 - fakeImport(
694 - new Promise(resolve =>
695 - resolve(function Foo() {
696 - return <div />;
697 - }),
698 - ),
699 - ),
700 - );
701 - ReactDOMServer.renderToString(<LazyFoo />);
702 - }).toThrow('ReactDOMServer does not yet support Suspense.');
703 - });
704 -
705 - it('throws when suspending on the server', () => {
706 - function AsyncFoo() {
707 - throw new Promise(() => {});
708 - }
709 -
710 - expect(() => {
711 - ReactDOMServer.renderToString(<AsyncFoo />);
712 - }).toThrow('ReactDOMServer does not yet support Suspense.');
713 - });
714 - }
715 -
679 it('does not get confused by throwing null', () => {
680 function Bad() {
681 // eslint-disable-next-line no-throw-literal
packages/react-dom/src/client/ReactDOMHostConfig.js
+11 -14
@@ -63,7 +63,6 @@ import {retryIfBlockedOn} from '../events/ReactDOMEventReplaying';
63
64 import {
65 enableClientRenderFallbackOnHydrationMismatch,
66 - enableSuspenseServerRenderer,
66 enableCreateEventHandleAPI,
67 enableScopeAPI,
68 } from 'shared/ReactFeatureFlags';
@@ -747,19 +746,17 @@ function getNextHydratable(node) {
746 if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) {
747 break;
748 }
750 - if (enableSuspenseServerRenderer) {
751 - if (nodeType === COMMENT_NODE) {
752 - const nodeData = (node: any).data;
753 - if (
754 - nodeData === SUSPENSE_START_DATA ||
755 - nodeData === SUSPENSE_FALLBACK_START_DATA ||
756 - nodeData === SUSPENSE_PENDING_START_DATA
757 - ) {
758 - break;
759 - }
760 - if (nodeData === SUSPENSE_END_DATA) {
761 - return null;
762 - }
749 + if (nodeType === COMMENT_NODE) {
750 + const nodeData = (node: any).data;
751 + if (
752 + nodeData === SUSPENSE_START_DATA ||
753 + nodeData === SUSPENSE_FALLBACK_START_DATA ||
754 + nodeData === SUSPENSE_PENDING_START_DATA
755 + ) {
756 + break;
757 + }
758 + if (nodeData === SUSPENSE_END_DATA) {
759 + return null;
760 }
761 }
762 }
packages/react-dom/src/server/ReactPartialRenderer.js
+38 -47
@@ -21,7 +21,6 @@ import {
21 warnAboutDeprecatedLifecycles,
22 disableLegacyContext,
23 disableModulePatternComponents,
24 - enableSuspenseServerRenderer,
24 enableScopeAPI,
25 } from 'shared/ReactFeatureFlags';
26 import {
@@ -965,21 +964,17 @@ class ReactDOMServerRenderer {
964 outBuffer += this.render(child, frame.context, frame.domNamespace);
965 } catch (err) {
966 if (err != null && typeof err.then === 'function') {
968 - if (enableSuspenseServerRenderer) {
969 - if (this.suspenseDepth <= 0) {
970 - throw new Error(
971 - // TODO: include component name. This is a bit tricky with current factoring.
972 - 'A React component suspended while rendering, but no fallback UI was specified.\n' +
973 - '\n' +
974 - 'Add a <Suspense fallback=...> component higher in the tree to ' +
975 - 'provide a loading indicator or placeholder to display.',
976 - );
977 - }
978 -
979 - suspended = true;
980 - } else {
981 - throw new Error('ReactDOMServer does not yet support Suspense.');
967 + if (this.suspenseDepth <= 0) {
968 + throw new Error(
969 + // TODO: include component name. This is a bit tricky with current factoring.
970 + 'A React component suspended while rendering, but no fallback UI was specified.\n' +
971 + '\n' +
972 + 'Add a <Suspense fallback=...> component higher in the tree to ' +
973 + 'provide a loading indicator or placeholder to display.',
974 + );
975 }
976 +
977 + suspended = true;
978 } else {
979 throw err;
980 }
@@ -1097,39 +1092,35 @@ class ReactDOMServerRenderer {
1092 return '';
1093 }
1094 case REACT_SUSPENSE_TYPE: {
1100 - if (enableSuspenseServerRenderer) {
1101 - const fallback = ((nextChild: any): ReactElement).props.fallback;
1102 - const fallbackChildren = toArray(fallback);
1103 - const nextChildren = toArray(
1104 - ((nextChild: any): ReactElement).props.children,
1105 - );
1106 - const fallbackFrame: Frame = {
1107 - type: null,
1108 - domNamespace: parentNamespace,
1109 - children: fallbackChildren,
1110 - childIndex: 0,
1111 - context: context,
1112 - footer: '<!--/$-->',
1113 - };
1114 - const frame: Frame = {
1115 - fallbackFrame,
1116 - type: REACT_SUSPENSE_TYPE,
1117 - domNamespace: parentNamespace,
1118 - children: nextChildren,
1119 - childIndex: 0,
1120 - context: context,
1121 - footer: '<!--/$-->',
1122 - };
1123 - if (__DEV__) {
1124 - ((frame: any): FrameDev).debugElementStack = [];
1125 - ((fallbackFrame: any): FrameDev).debugElementStack = [];
1126 - }
1127 - this.stack.push(frame);
1128 - this.suspenseDepth++;
1129 - return '<!--$-->';
1130 - } else {
1131 - throw new Error('ReactDOMServer does not yet support Suspense.');
1095 + const fallback = ((nextChild: any): ReactElement).props.fallback;
1096 + const fallbackChildren = toArray(fallback);
1097 + const nextChildren = toArray(
1098 + ((nextChild: any): ReactElement).props.children,
1099 + );
1100 + const fallbackFrame: Frame = {
1101 + type: null,
1102 + domNamespace: parentNamespace,
1103 + children: fallbackChildren,
1104 + childIndex: 0,
1105 + context: context,
1106 + footer: '<!--/$-->',
1107 + };
1108 + const frame: Frame = {
1109 + fallbackFrame,
1110 + type: REACT_SUSPENSE_TYPE,
1111 + domNamespace: parentNamespace,
1112 + children: nextChildren,
1113 + childIndex: 0,
1114 + context: context,
1115 + footer: '<!--/$-->',
1116 + };
1117 + if (__DEV__) {
1118 + ((frame: any): FrameDev).debugElementStack = [];
1119 + ((fallbackFrame: any): FrameDev).debugElementStack = [];
1120 }
1121 + this.stack.push(frame);
1122 + this.suspenseDepth++;
1123 + return '<!--$-->';
1124 }
1125 // eslint-disable-next-line-no-fallthrough
1126 case REACT_SCOPE_TYPE: {
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+72 -79
@@ -96,7 +96,6 @@ import {
96 disableModulePatternComponents,
97 enableProfilerCommitHooks,
98 enableProfilerTimer,
99 - enableSuspenseServerRenderer,
99 warnAboutDefaultPropsOnFunctionComponents,
100 enableScopeAPI,
101 enableCache,
@@ -2134,17 +2133,15 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2133 // If we're currently hydrating, try to hydrate this boundary.
2134 tryToClaimNextHydratableInstance(workInProgress);
2135 // This could've been a dehydrated suspense component.
2137 - if (enableSuspenseServerRenderer) {
2138 - const suspenseState: null | SuspenseState = workInProgress.memoizedState;
2139 - if (suspenseState !== null) {
2140 - const dehydrated = suspenseState.dehydrated;
2141 - if (dehydrated !== null) {
2142 - return mountDehydratedSuspenseComponent(
2143 - workInProgress,
2144 - dehydrated,
2145 - renderLanes,
2146 - );
2147 - }
2136 + const suspenseState: null | SuspenseState = workInProgress.memoizedState;
2137 + if (suspenseState !== null) {
2138 + const dehydrated = suspenseState.dehydrated;
2139 + if (dehydrated !== null) {
2140 + return mountDehydratedSuspenseComponent(
2141 + workInProgress,
2142 + dehydrated,
2143 + renderLanes,
2144 + );
2145 }
2146 }
2147
@@ -2220,59 +2217,57 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2217 // The current tree is already showing a fallback
2218
2219 // Special path for hydration
2223 - if (enableSuspenseServerRenderer) {
2224 - const dehydrated = prevState.dehydrated;
2225 - if (dehydrated !== null) {
2226 - if (!didSuspend) {
2227 - return updateDehydratedSuspenseComponent(
2228 - current,
2229 - workInProgress,
2230 - dehydrated,
2231 - prevState,
2232 - renderLanes,
2233 - );
2234 - } else if (workInProgress.flags & ForceClientRender) {
2235 - // Something errored during hydration. Try again without hydrating.
2236 - workInProgress.flags &= ~ForceClientRender;
2237 - return retrySuspenseComponentWithoutHydrating(
2238 - current,
2239 - workInProgress,
2240 - renderLanes,
2241 - new Error(
2242 - 'There was an error while hydrating this Suspense boundary. ' +
2243 - 'Switched to client rendering.',
2244 - ),
2245 - );
2246 - } else if (
2247 - (workInProgress.memoizedState: null | SuspenseState) !== null
2248 - ) {
2249 - // Something suspended and we should still be in dehydrated mode.
2250 - // Leave the existing child in place.
2251 - workInProgress.child = current.child;
2252 - // The dehydrated completion pass expects this flag to be there
2253 - // but the normal suspense pass doesn't.
2254 - workInProgress.flags |= DidCapture;
2255 - return null;
2256 - } else {
2257 - // Suspended but we should no longer be in dehydrated mode.
2258 - // Therefore we now have to render the fallback.
2259 - renderDidSuspendDelayIfPossible();
2260 - const nextPrimaryChildren = nextProps.children;
2261 - const nextFallbackChildren = nextProps.fallback;
2262 - const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating(
2263 - current,
2264 - workInProgress,
2265 - nextPrimaryChildren,
2266 - nextFallbackChildren,
2267 - renderLanes,
2268 - );
2269 - const primaryChildFragment: Fiber = (workInProgress.child: any);
2270 - primaryChildFragment.memoizedState = mountSuspenseOffscreenState(
2271 - renderLanes,
2272 - );
2273 - workInProgress.memoizedState = SUSPENDED_MARKER;
2274 - return fallbackChildFragment;
2275 - }
2220 + const dehydrated = prevState.dehydrated;
2221 + if (dehydrated !== null) {
2222 + if (!didSuspend) {
2223 + return updateDehydratedSuspenseComponent(
2224 + current,
2225 + workInProgress,
2226 + dehydrated,
2227 + prevState,
2228 + renderLanes,
2229 + );
2230 + } else if (workInProgress.flags & ForceClientRender) {
2231 + // Something errored during hydration. Try again without hydrating.
2232 + workInProgress.flags &= ~ForceClientRender;
2233 + return retrySuspenseComponentWithoutHydrating(
2234 + current,
2235 + workInProgress,
2236 + renderLanes,
2237 + new Error(
2238 + 'There was an error while hydrating this Suspense boundary. ' +
2239 + 'Switched to client rendering.',
2240 + ),
2241 + );
2242 + } else if (
2243 + (workInProgress.memoizedState: null | SuspenseState) !== null
2244 + ) {
2245 + // Something suspended and we should still be in dehydrated mode.
2246 + // Leave the existing child in place.
2247 + workInProgress.child = current.child;
2248 + // The dehydrated completion pass expects this flag to be there
2249 + // but the normal suspense pass doesn't.
2250 + workInProgress.flags |= DidCapture;
2251 + return null;
2252 + } else {
2253 + // Suspended but we should no longer be in dehydrated mode.
2254 + // Therefore we now have to render the fallback.
2255 + renderDidSuspendDelayIfPossible();
2256 + const nextPrimaryChildren = nextProps.children;
2257 + const nextFallbackChildren = nextProps.fallback;
2258 + const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating(
2259 + current,
2260 + workInProgress,
2261 + nextPrimaryChildren,
2262 + nextFallbackChildren,
2263 + renderLanes,
2264 + );
2265 + const primaryChildFragment: Fiber = (workInProgress.child: any);
2266 + primaryChildFragment.memoizedState = mountSuspenseOffscreenState(
2267 + renderLanes,
2268 + );
2269 + workInProgress.memoizedState = SUSPENDED_MARKER;
2270 + return fallbackChildFragment;
2271 }
2272 }
2273
@@ -3657,20 +3652,18 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
3652 case SuspenseComponent: {
3653 const state: SuspenseState | null = workInProgress.memoizedState;
3654 if (state !== null) {
3660 - if (enableSuspenseServerRenderer) {
3661 - if (state.dehydrated !== null) {
3662 - pushSuspenseContext(
3663 - workInProgress,
3664 - setDefaultShallowSuspenseContext(suspenseStackCursor.current),
3665 - );
3666 - // We know that this component will suspend again because if it has
3667 - // been unsuspended it has committed as a resolved Suspense component.
3668 - // If it needs to be retried, it should have work scheduled on it.
3669 - workInProgress.flags |= DidCapture;
3670 - // We should never render the children of a dehydrated boundary until we
3671 - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork.
3672 - return null;
3673 - }
3655 + if (state.dehydrated !== null) {
3656 + pushSuspenseContext(
3657 + workInProgress,
3658 + setDefaultShallowSuspenseContext(suspenseStackCursor.current),
3659 + );
3660 + // We know that this component will suspend again because if it has
3661 + // been unsuspended it has committed as a resolved Suspense component.
3662 + // If it needs to be retried, it should have work scheduled on it.
3663 + workInProgress.flags |= DidCapture;
3664 + // We should never render the children of a dehydrated boundary until we
3665 + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork.
3666 + return null;
3667 }
3668
3669 // If this boundary is currently timed out, we need to decide
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+72 -79
@@ -96,7 +96,6 @@ import {
96 disableModulePatternComponents,
97 enableProfilerCommitHooks,
98 enableProfilerTimer,
99 - enableSuspenseServerRenderer,
99 warnAboutDefaultPropsOnFunctionComponents,
100 enableScopeAPI,
101 enableCache,
@@ -2134,17 +2133,15 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2133 // If we're currently hydrating, try to hydrate this boundary.
2134 tryToClaimNextHydratableInstance(workInProgress);
2135 // This could've been a dehydrated suspense component.
2137 - if (enableSuspenseServerRenderer) {
2138 - const suspenseState: null | SuspenseState = workInProgress.memoizedState;
2139 - if (suspenseState !== null) {
2140 - const dehydrated = suspenseState.dehydrated;
2141 - if (dehydrated !== null) {
2142 - return mountDehydratedSuspenseComponent(
2143 - workInProgress,
2144 - dehydrated,
2145 - renderLanes,
2146 - );
2147 - }
2136 + const suspenseState: null | SuspenseState = workInProgress.memoizedState;
2137 + if (suspenseState !== null) {
2138 + const dehydrated = suspenseState.dehydrated;
2139 + if (dehydrated !== null) {
2140 + return mountDehydratedSuspenseComponent(
2141 + workInProgress,
2142 + dehydrated,
2143 + renderLanes,
2144 + );
2145 }
2146 }
2147
@@ -2220,59 +2217,57 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2217 // The current tree is already showing a fallback
2218
2219 // Special path for hydration
2223 - if (enableSuspenseServerRenderer) {
2224 - const dehydrated = prevState.dehydrated;
2225 - if (dehydrated !== null) {
2226 - if (!didSuspend) {
2227 - return updateDehydratedSuspenseComponent(
2228 - current,
2229 - workInProgress,
2230 - dehydrated,
2231 - prevState,
2232 - renderLanes,
2233 - );
2234 - } else if (workInProgress.flags & ForceClientRender) {
2235 - // Something errored during hydration. Try again without hydrating.
2236 - workInProgress.flags &= ~ForceClientRender;
2237 - return retrySuspenseComponentWithoutHydrating(
2238 - current,
2239 - workInProgress,
2240 - renderLanes,
2241 - new Error(
2242 - 'There was an error while hydrating this Suspense boundary. ' +
2243 - 'Switched to client rendering.',
2244 - ),
2245 - );
2246 - } else if (
2247 - (workInProgress.memoizedState: null | SuspenseState) !== null
2248 - ) {
2249 - // Something suspended and we should still be in dehydrated mode.
2250 - // Leave the existing child in place.
2251 - workInProgress.child = current.child;
2252 - // The dehydrated completion pass expects this flag to be there
2253 - // but the normal suspense pass doesn't.
2254 - workInProgress.flags |= DidCapture;
2255 - return null;
2256 - } else {
2257 - // Suspended but we should no longer be in dehydrated mode.
2258 - // Therefore we now have to render the fallback.
2259 - renderDidSuspendDelayIfPossible();
2260 - const nextPrimaryChildren = nextProps.children;
2261 - const nextFallbackChildren = nextProps.fallback;
2262 - const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating(
2263 - current,
2264 - workInProgress,
2265 - nextPrimaryChildren,
2266 - nextFallbackChildren,
2267 - renderLanes,
2268 - );
2269 - const primaryChildFragment: Fiber = (workInProgress.child: any);
2270 - primaryChildFragment.memoizedState = mountSuspenseOffscreenState(
2271 - renderLanes,
2272 - );
2273 - workInProgress.memoizedState = SUSPENDED_MARKER;
2274 - return fallbackChildFragment;
2275 - }
2220 + const dehydrated = prevState.dehydrated;
2221 + if (dehydrated !== null) {
2222 + if (!didSuspend) {
2223 + return updateDehydratedSuspenseComponent(
2224 + current,
2225 + workInProgress,
2226 + dehydrated,
2227 + prevState,
2228 + renderLanes,
2229 + );
2230 + } else if (workInProgress.flags & ForceClientRender) {
2231 + // Something errored during hydration. Try again without hydrating.
2232 + workInProgress.flags &= ~ForceClientRender;
2233 + return retrySuspenseComponentWithoutHydrating(
2234 + current,
2235 + workInProgress,
2236 + renderLanes,
2237 + new Error(
2238 + 'There was an error while hydrating this Suspense boundary. ' +
2239 + 'Switched to client rendering.',
2240 + ),
2241 + );
2242 + } else if (
2243 + (workInProgress.memoizedState: null | SuspenseState) !== null
2244 + ) {
2245 + // Something suspended and we should still be in dehydrated mode.
2246 + // Leave the existing child in place.
2247 + workInProgress.child = current.child;
2248 + // The dehydrated completion pass expects this flag to be there
2249 + // but the normal suspense pass doesn't.
2250 + workInProgress.flags |= DidCapture;
2251 + return null;
2252 + } else {
2253 + // Suspended but we should no longer be in dehydrated mode.
2254 + // Therefore we now have to render the fallback.
2255 + renderDidSuspendDelayIfPossible();
2256 + const nextPrimaryChildren = nextProps.children;
2257 + const nextFallbackChildren = nextProps.fallback;
2258 + const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating(
2259 + current,
2260 + workInProgress,
2261 + nextPrimaryChildren,
2262 + nextFallbackChildren,
2263 + renderLanes,
2264 + );
2265 + const primaryChildFragment: Fiber = (workInProgress.child: any);
2266 + primaryChildFragment.memoizedState = mountSuspenseOffscreenState(
2267 + renderLanes,
2268 + );
2269 + workInProgress.memoizedState = SUSPENDED_MARKER;
2270 + return fallbackChildFragment;
2271 }
2272 }
2273
@@ -3657,20 +3652,18 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
3652 case SuspenseComponent: {
3653 const state: SuspenseState | null = workInProgress.memoizedState;
3654 if (state !== null) {
3660 - if (enableSuspenseServerRenderer) {
3661 - if (state.dehydrated !== null) {
3662 - pushSuspenseContext(
3663 - workInProgress,
3664 - setDefaultShallowSuspenseContext(suspenseStackCursor.current),
3665 - );
3666 - // We know that this component will suspend again because if it has
3667 - // been unsuspended it has committed as a resolved Suspense component.
3668 - // If it needs to be retried, it should have work scheduled on it.
3669 - workInProgress.flags |= DidCapture;
3670 - // We should never render the children of a dehydrated boundary until we
3671 - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork.
3672 - return null;
3673 - }
3655 + if (state.dehydrated !== null) {
3656 + pushSuspenseContext(
3657 + workInProgress,
3658 + setDefaultShallowSuspenseContext(suspenseStackCursor.current),
3659 + );
3660 + // We know that this component will suspend again because if it has
3661 + // been unsuspended it has committed as a resolved Suspense component.
3662 + // If it needs to be retried, it should have work scheduled on it.
3663 + workInProgress.flags |= DidCapture;
3664 + // We should never render the children of a dehydrated boundary until we
3665 + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork.
3666 + return null;
3667 }
3668
3669 // If this boundary is currently timed out, we need to decide
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+21 -24
@@ -34,7 +34,6 @@ import {
34 enableProfilerCommitHooks,
35 enableProfilerNestedUpdatePhase,
36 enableSchedulingProfiler,
37 - enableSuspenseServerRenderer,
37 enableSuspenseCallback,
38 enableScopeAPI,
39 enableStrictEffects,
@@ -1652,33 +1651,31 @@ function commitDeletionEffectsOnFiber(
1651 return;
1652 }
1653 case DehydratedFragment: {
1655 - if (enableSuspenseServerRenderer) {
1656 - if (enableSuspenseCallback) {
1657 - const hydrationCallbacks = finishedRoot.hydrationCallbacks;
1658 - if (hydrationCallbacks !== null) {
1659 - const onDeleted = hydrationCallbacks.onDeleted;
1660 - if (onDeleted) {
1661 - onDeleted((deletedFiber.stateNode: SuspenseInstance));
1662 - }
1654 + if (enableSuspenseCallback) {
1655 + const hydrationCallbacks = finishedRoot.hydrationCallbacks;
1656 + if (hydrationCallbacks !== null) {
1657 + const onDeleted = hydrationCallbacks.onDeleted;
1658 + if (onDeleted) {
1659 + onDeleted((deletedFiber.stateNode: SuspenseInstance));
1660 }
1661 }
1662 + }
1663
1666 - // Dehydrated fragments don't have any children
1664 + // Dehydrated fragments don't have any children
1665
1668 - // Delete the dehydrated suspense boundary and all of its content.
1669 - if (supportsMutation) {
1670 - if (hostParent !== null) {
1671 - if (hostParentIsContainer) {
1672 - clearSuspenseBoundaryFromContainer(
1673 - ((hostParent: any): Container),
1674 - (deletedFiber.stateNode: SuspenseInstance),
1675 - );
1676 - } else {
1677 - clearSuspenseBoundary(
1678 - ((hostParent: any): Instance),
1679 - (deletedFiber.stateNode: SuspenseInstance),
1680 - );
1681 - }
1666 + // Delete the dehydrated suspense boundary and all of its content.
1667 + if (supportsMutation) {
1668 + if (hostParent !== null) {
1669 + if (hostParentIsContainer) {
1670 + clearSuspenseBoundaryFromContainer(
1671 + ((hostParent: any): Container),
1672 + (deletedFiber.stateNode: SuspenseInstance),
1673 + );
1674 + } else {
1675 + clearSuspenseBoundary(
1676 + ((hostParent: any): Instance),
1677 + (deletedFiber.stateNode: SuspenseInstance),
1678 + );
1679 }
1680 }
1681 }
packages/react-reconciler/src/ReactFiberCommitWork.old.js
+21 -24
@@ -34,7 +34,6 @@ import {
34 enableProfilerCommitHooks,
35 enableProfilerNestedUpdatePhase,
36 enableSchedulingProfiler,
37 - enableSuspenseServerRenderer,
37 enableSuspenseCallback,
38 enableScopeAPI,
39 enableStrictEffects,
@@ -1652,33 +1651,31 @@ function commitDeletionEffectsOnFiber(
1651 return;
1652 }
1653 case DehydratedFragment: {
1655 - if (enableSuspenseServerRenderer) {
1656 - if (enableSuspenseCallback) {
1657 - const hydrationCallbacks = finishedRoot.hydrationCallbacks;
1658 - if (hydrationCallbacks !== null) {
1659 - const onDeleted = hydrationCallbacks.onDeleted;
1660 - if (onDeleted) {
1661 - onDeleted((deletedFiber.stateNode: SuspenseInstance));
1662 - }
1654 + if (enableSuspenseCallback) {
1655 + const hydrationCallbacks = finishedRoot.hydrationCallbacks;
1656 + if (hydrationCallbacks !== null) {
1657 + const onDeleted = hydrationCallbacks.onDeleted;
1658 + if (onDeleted) {
1659 + onDeleted((deletedFiber.stateNode: SuspenseInstance));
1660 }
1661 }
1662 + }
1663
1666 - // Dehydrated fragments don't have any children
1664 + // Dehydrated fragments don't have any children
1665
1668 - // Delete the dehydrated suspense boundary and all of its content.
1669 - if (supportsMutation) {
1670 - if (hostParent !== null) {
1671 - if (hostParentIsContainer) {
1672 - clearSuspenseBoundaryFromContainer(
1673 - ((hostParent: any): Container),
1674 - (deletedFiber.stateNode: SuspenseInstance),
1675 - );
1676 - } else {
1677 - clearSuspenseBoundary(
1678 - ((hostParent: any): Instance),
1679 - (deletedFiber.stateNode: SuspenseInstance),
1680 - );
1681 - }
1666 + // Delete the dehydrated suspense boundary and all of its content.
1667 + if (supportsMutation) {
1668 + if (hostParent !== null) {
1669 + if (hostParentIsContainer) {
1670 + clearSuspenseBoundaryFromContainer(
1671 + ((hostParent: any): Container),
1672 + (deletedFiber.stateNode: SuspenseInstance),
1673 + );
1674 + } else {
1675 + clearSuspenseBoundary(
1676 + ((hostParent: any): Instance),
1677 + (deletedFiber.stateNode: SuspenseInstance),
1678 + );
1679 }
1680 }
1681 }
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+66 -70
@@ -138,7 +138,6 @@ import {
138 } from './ReactFiberHydrationContext.new';
139 import {
140 enableSuspenseCallback,
141 - enableSuspenseServerRenderer,
141 enableScopeAPI,
142 enableProfilerTimer,
143 enableCache,
@@ -1066,85 +1065,82 @@ function completeWork(
1065 popSuspenseContext(workInProgress);
1066 const nextState: null | SuspenseState = workInProgress.memoizedState;
1067
1069 - if (enableSuspenseServerRenderer) {
1070 - if (
1071 - enableClientRenderFallbackOnHydrationMismatch &&
1072 - hasUnhydratedTailNodes() &&
1073 - (workInProgress.mode & ConcurrentMode) !== NoMode &&
1074 - (workInProgress.flags & DidCapture) === NoFlags
1075 - ) {
1076 - warnIfUnhydratedTailNodes(workInProgress);
1077 - resetHydrationState();
1078 - workInProgress.flags |=
1079 - ForceClientRender | Incomplete | ShouldCapture;
1080 - return workInProgress;
1081 - }
1082 - if (nextState !== null && nextState.dehydrated !== null) {
1083 - // We might be inside a hydration state the first time we're picking up this
1084 - // Suspense boundary, and also after we've reentered it for further hydration.
1085 - const wasHydrated = popHydrationState(workInProgress);
1086 - if (current === null) {
1087 - if (!wasHydrated) {
1088 - throw new Error(
1089 - 'A dehydrated suspense component was completed without a hydrated node. ' +
1090 - 'This is probably a bug in React.',
1091 - );
1092 - }
1093 - prepareToHydrateHostSuspenseInstance(workInProgress);
1094 - bubbleProperties(workInProgress);
1095 - if (enableProfilerTimer) {
1096 - if ((workInProgress.mode & ProfileMode) !== NoMode) {
1097 - const isTimedOutSuspense = nextState !== null;
1098 - if (isTimedOutSuspense) {
1099 - // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1100 - const primaryChildFragment = workInProgress.child;
1101 - if (primaryChildFragment !== null) {
1102 - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1103 - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1104 - }
1068 + if (
1069 + enableClientRenderFallbackOnHydrationMismatch &&
1070 + hasUnhydratedTailNodes() &&
1071 + (workInProgress.mode & ConcurrentMode) !== NoMode &&
1072 + (workInProgress.flags & DidCapture) === NoFlags
1073 + ) {
1074 + warnIfUnhydratedTailNodes(workInProgress);
1075 + resetHydrationState();
1076 + workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture;
1077 + return workInProgress;
1078 + }
1079 + if (nextState !== null && nextState.dehydrated !== null) {
1080 + // We might be inside a hydration state the first time we're picking up this
1081 + // Suspense boundary, and also after we've reentered it for further hydration.
1082 + const wasHydrated = popHydrationState(workInProgress);
1083 + if (current === null) {
1084 + if (!wasHydrated) {
1085 + throw new Error(
1086 + 'A dehydrated suspense component was completed without a hydrated node. ' +
1087 + 'This is probably a bug in React.',
1088 + );
1089 + }
1090 + prepareToHydrateHostSuspenseInstance(workInProgress);
1091 + bubbleProperties(workInProgress);
1092 + if (enableProfilerTimer) {
1093 + if ((workInProgress.mode & ProfileMode) !== NoMode) {
1094 + const isTimedOutSuspense = nextState !== null;
1095 + if (isTimedOutSuspense) {
1096 + // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1097 + const primaryChildFragment = workInProgress.child;
1098 + if (primaryChildFragment !== null) {
1099 + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1100 + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1101 }
1102 }
1103 }
1108 - return null;
1109 - } else {
1110 - // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration
1111 - // state since we're now exiting out of it. popHydrationState doesn't do that for us.
1112 - resetHydrationState();
1113 - if ((workInProgress.flags & DidCapture) === NoFlags) {
1114 - // This boundary did not suspend so it's now hydrated and unsuspended.
1115 - workInProgress.memoizedState = null;
1116 - }
1117 - // If nothing suspended, we need to schedule an effect to mark this boundary
1118 - // as having hydrated so events know that they're free to be invoked.
1119 - // It's also a signal to replay events and the suspense callback.
1120 - // If something suspended, schedule an effect to attach retry listeners.
1121 - // So we might as well always mark this.
1122 - workInProgress.flags |= Update;
1123 - bubbleProperties(workInProgress);
1124 - if (enableProfilerTimer) {
1125 - if ((workInProgress.mode & ProfileMode) !== NoMode) {
1126 - const isTimedOutSuspense = nextState !== null;
1127 - if (isTimedOutSuspense) {
1128 - // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1129 - const primaryChildFragment = workInProgress.child;
1130 - if (primaryChildFragment !== null) {
1131 - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1132 - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1133 - }
1104 + }
1105 + return null;
1106 + } else {
1107 + // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration
1108 + // state since we're now exiting out of it. popHydrationState doesn't do that for us.
1109 + resetHydrationState();
1110 + if ((workInProgress.flags & DidCapture) === NoFlags) {
1111 + // This boundary did not suspend so it's now hydrated and unsuspended.
1112 + workInProgress.memoizedState = null;
1113 + }
1114 + // If nothing suspended, we need to schedule an effect to mark this boundary
1115 + // as having hydrated so events know that they're free to be invoked.
1116 + // It's also a signal to replay events and the suspense callback.
1117 + // If something suspended, schedule an effect to attach retry listeners.
1118 + // So we might as well always mark this.
1119 + workInProgress.flags |= Update;
1120 + bubbleProperties(workInProgress);
1121 + if (enableProfilerTimer) {
1122 + if ((workInProgress.mode & ProfileMode) !== NoMode) {
1123 + const isTimedOutSuspense = nextState !== null;
1124 + if (isTimedOutSuspense) {
1125 + // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1126 + const primaryChildFragment = workInProgress.child;
1127 + if (primaryChildFragment !== null) {
1128 + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1129 + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1130 }
1131 }
1132 }
1137 - return null;
1133 }
1134 + return null;
1135 }
1140 -
1141 - // Successfully completed this tree. If this was a forced client render,
1142 - // there may have been recoverable errors during first hydration
1143 - // attempt. If so, add them to a queue so we can log them in the
1144 - // commit phase.
1145 - upgradeHydrationErrorsToRecoverable();
1136 }
1137
1138 + // Successfully completed this tree. If this was a forced client render,
1139 + // there may have been recoverable errors during first hydration
1140 + // attempt. If so, add them to a queue so we can log them in the
1141 + // commit phase.
1142 + upgradeHydrationErrorsToRecoverable();
1143 +
1144 if ((workInProgress.flags & DidCapture) !== NoFlags) {
1145 // Something suspended. Re-render with the fallback children.
1146 workInProgress.lanes = renderLanes;
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+66 -70
@@ -138,7 +138,6 @@ import {
138 } from './ReactFiberHydrationContext.old';
139 import {
140 enableSuspenseCallback,
141 - enableSuspenseServerRenderer,
141 enableScopeAPI,
142 enableProfilerTimer,
143 enableCache,
@@ -1066,85 +1065,82 @@ function completeWork(
1065 popSuspenseContext(workInProgress);
1066 const nextState: null | SuspenseState = workInProgress.memoizedState;
1067
1069 - if (enableSuspenseServerRenderer) {
1070 - if (
1071 - enableClientRenderFallbackOnHydrationMismatch &&
1072 - hasUnhydratedTailNodes() &&
1073 - (workInProgress.mode & ConcurrentMode) !== NoMode &&
1074 - (workInProgress.flags & DidCapture) === NoFlags
1075 - ) {
1076 - warnIfUnhydratedTailNodes(workInProgress);
1077 - resetHydrationState();
1078 - workInProgress.flags |=
1079 - ForceClientRender | Incomplete | ShouldCapture;
1080 - return workInProgress;
1081 - }
1082 - if (nextState !== null && nextState.dehydrated !== null) {
1083 - // We might be inside a hydration state the first time we're picking up this
1084 - // Suspense boundary, and also after we've reentered it for further hydration.
1085 - const wasHydrated = popHydrationState(workInProgress);
1086 - if (current === null) {
1087 - if (!wasHydrated) {
1088 - throw new Error(
1089 - 'A dehydrated suspense component was completed without a hydrated node. ' +
1090 - 'This is probably a bug in React.',
1091 - );
1092 - }
1093 - prepareToHydrateHostSuspenseInstance(workInProgress);
1094 - bubbleProperties(workInProgress);
1095 - if (enableProfilerTimer) {
1096 - if ((workInProgress.mode & ProfileMode) !== NoMode) {
1097 - const isTimedOutSuspense = nextState !== null;
1098 - if (isTimedOutSuspense) {
1099 - // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1100 - const primaryChildFragment = workInProgress.child;
1101 - if (primaryChildFragment !== null) {
1102 - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1103 - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1104 - }
1068 + if (
1069 + enableClientRenderFallbackOnHydrationMismatch &&
1070 + hasUnhydratedTailNodes() &&
1071 + (workInProgress.mode & ConcurrentMode) !== NoMode &&
1072 + (workInProgress.flags & DidCapture) === NoFlags
1073 + ) {
1074 + warnIfUnhydratedTailNodes(workInProgress);
1075 + resetHydrationState();
1076 + workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture;
1077 + return workInProgress;
1078 + }
1079 + if (nextState !== null && nextState.dehydrated !== null) {
1080 + // We might be inside a hydration state the first time we're picking up this
1081 + // Suspense boundary, and also after we've reentered it for further hydration.
1082 + const wasHydrated = popHydrationState(workInProgress);
1083 + if (current === null) {
1084 + if (!wasHydrated) {
1085 + throw new Error(
1086 + 'A dehydrated suspense component was completed without a hydrated node. ' +
1087 + 'This is probably a bug in React.',
1088 + );
1089 + }
1090 + prepareToHydrateHostSuspenseInstance(workInProgress);
1091 + bubbleProperties(workInProgress);
1092 + if (enableProfilerTimer) {
1093 + if ((workInProgress.mode & ProfileMode) !== NoMode) {
1094 + const isTimedOutSuspense = nextState !== null;
1095 + if (isTimedOutSuspense) {
1096 + // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1097 + const primaryChildFragment = workInProgress.child;
1098 + if (primaryChildFragment !== null) {
1099 + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1100 + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1101 }
1102 }
1103 }
1108 - return null;
1109 - } else {
1110 - // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration
1111 - // state since we're now exiting out of it. popHydrationState doesn't do that for us.
1112 - resetHydrationState();
1113 - if ((workInProgress.flags & DidCapture) === NoFlags) {
1114 - // This boundary did not suspend so it's now hydrated and unsuspended.
1115 - workInProgress.memoizedState = null;
1116 - }
1117 - // If nothing suspended, we need to schedule an effect to mark this boundary
1118 - // as having hydrated so events know that they're free to be invoked.
1119 - // It's also a signal to replay events and the suspense callback.
1120 - // If something suspended, schedule an effect to attach retry listeners.
1121 - // So we might as well always mark this.
1122 - workInProgress.flags |= Update;
1123 - bubbleProperties(workInProgress);
1124 - if (enableProfilerTimer) {
1125 - if ((workInProgress.mode & ProfileMode) !== NoMode) {
1126 - const isTimedOutSuspense = nextState !== null;
1127 - if (isTimedOutSuspense) {
1128 - // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1129 - const primaryChildFragment = workInProgress.child;
1130 - if (primaryChildFragment !== null) {
1131 - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1132 - workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1133 - }
1104 + }
1105 + return null;
1106 + } else {
1107 + // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration
1108 + // state since we're now exiting out of it. popHydrationState doesn't do that for us.
1109 + resetHydrationState();
1110 + if ((workInProgress.flags & DidCapture) === NoFlags) {
1111 + // This boundary did not suspend so it's now hydrated and unsuspended.
1112 + workInProgress.memoizedState = null;
1113 + }
1114 + // If nothing suspended, we need to schedule an effect to mark this boundary
1115 + // as having hydrated so events know that they're free to be invoked.
1116 + // It's also a signal to replay events and the suspense callback.
1117 + // If something suspended, schedule an effect to attach retry listeners.
1118 + // So we might as well always mark this.
1119 + workInProgress.flags |= Update;
1120 + bubbleProperties(workInProgress);
1121 + if (enableProfilerTimer) {
1122 + if ((workInProgress.mode & ProfileMode) !== NoMode) {
1123 + const isTimedOutSuspense = nextState !== null;
1124 + if (isTimedOutSuspense) {
1125 + // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1126 + const primaryChildFragment = workInProgress.child;
1127 + if (primaryChildFragment !== null) {
1128 + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator
1129 + workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1130 }
1131 }
1132 }
1137 - return null;
1133 }
1134 + return null;
1135 }
1140 -
1141 - // Successfully completed this tree. If this was a forced client render,
1142 - // there may have been recoverable errors during first hydration
1143 - // attempt. If so, add them to a queue so we can log them in the
1144 - // commit phase.
1145 - upgradeHydrationErrorsToRecoverable();
1136 }
1137
1138 + // Successfully completed this tree. If this was a forced client render,
1139 + // there may have been recoverable errors during first hydration
1140 + // attempt. If so, add them to a queue so we can log them in the
1141 + // commit phase.
1142 + upgradeHydrationErrorsToRecoverable();
1143 +
1144 if ((workInProgress.flags & DidCapture) !== NoFlags) {
1145 // Something suspended. Re-render with the fallback children.
1146 workInProgress.lanes = renderLanes;
packages/react-reconciler/src/ReactFiberHydrationContext.new.js
+24 -29
@@ -68,10 +68,7 @@ import {
68 didNotFindHydratableTextInstance,
69 didNotFindHydratableSuspenseInstance,
70 } from './ReactFiberHostConfig';
71 -import {
72 - enableClientRenderFallbackOnHydrationMismatch,
73 - enableSuspenseServerRenderer,
74 -} from 'shared/ReactFeatureFlags';
71 +import {enableClientRenderFallbackOnHydrationMismatch} from 'shared/ReactFeatureFlags';
72 import {OffscreenLane} from './ReactFiberLane.new';
73 import {
74 getSuspendedTreeContext,
@@ -347,32 +344,30 @@ function tryHydrate(fiber, nextInstance) {
344 return false;
345 }
346 case SuspenseComponent: {
350 - if (enableSuspenseServerRenderer) {
351 - const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance(
352 - nextInstance,
347 + const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance(
348 + nextInstance,
349 + );
350 + if (suspenseInstance !== null) {
351 + const suspenseState: SuspenseState = {
352 + dehydrated: suspenseInstance,
353 + treeContext: getSuspendedTreeContext(),
354 + retryLane: OffscreenLane,
355 + };
356 + fiber.memoizedState = suspenseState;
357 + // Store the dehydrated fragment as a child fiber.
358 + // This simplifies the code for getHostSibling and deleting nodes,
359 + // since it doesn't have to consider all Suspense boundaries and
360 + // check if they're dehydrated ones or not.
361 + const dehydratedFragment = createFiberFromDehydratedFragment(
362 + suspenseInstance,
363 );
354 - if (suspenseInstance !== null) {
355 - const suspenseState: SuspenseState = {
356 - dehydrated: suspenseInstance,
357 - treeContext: getSuspendedTreeContext(),
358 - retryLane: OffscreenLane,
359 - };
360 - fiber.memoizedState = suspenseState;
361 - // Store the dehydrated fragment as a child fiber.
362 - // This simplifies the code for getHostSibling and deleting nodes,
363 - // since it doesn't have to consider all Suspense boundaries and
364 - // check if they're dehydrated ones or not.
365 - const dehydratedFragment = createFiberFromDehydratedFragment(
366 - suspenseInstance,
367 - );
368 - dehydratedFragment.return = fiber;
369 - fiber.child = dehydratedFragment;
370 - hydrationParentFiber = fiber;
371 - // While a Suspense Instance does have children, we won't step into
372 - // it during the first pass. Instead, we'll reenter it later.
373 - nextHydratableInstance = null;
374 - return true;
375 - }
364 + dehydratedFragment.return = fiber;
365 + fiber.child = dehydratedFragment;
366 + hydrationParentFiber = fiber;
367 + // While a Suspense Instance does have children, we won't step into
368 + // it during the first pass. Instead, we'll reenter it later.
369 + nextHydratableInstance = null;
370 + return true;
371 }
372 return false;
373 }
packages/react-reconciler/src/ReactFiberHydrationContext.old.js
+24 -29
@@ -68,10 +68,7 @@ import {
68 didNotFindHydratableTextInstance,
69 didNotFindHydratableSuspenseInstance,
70 } from './ReactFiberHostConfig';
71 -import {
72 - enableClientRenderFallbackOnHydrationMismatch,
73 - enableSuspenseServerRenderer,
74 -} from 'shared/ReactFeatureFlags';
71 +import {enableClientRenderFallbackOnHydrationMismatch} from 'shared/ReactFeatureFlags';
72 import {OffscreenLane} from './ReactFiberLane.old';
73 import {
74 getSuspendedTreeContext,
@@ -347,32 +344,30 @@ function tryHydrate(fiber, nextInstance) {
344 return false;
345 }
346 case SuspenseComponent: {
350 - if (enableSuspenseServerRenderer) {
351 - const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance(
352 - nextInstance,
347 + const suspenseInstance: null | SuspenseInstance = canHydrateSuspenseInstance(
348 + nextInstance,
349 + );
350 + if (suspenseInstance !== null) {
351 + const suspenseState: SuspenseState = {
352 + dehydrated: suspenseInstance,
353 + treeContext: getSuspendedTreeContext(),
354 + retryLane: OffscreenLane,
355 + };
356 + fiber.memoizedState = suspenseState;
357 + // Store the dehydrated fragment as a child fiber.
358 + // This simplifies the code for getHostSibling and deleting nodes,
359 + // since it doesn't have to consider all Suspense boundaries and
360 + // check if they're dehydrated ones or not.
361 + const dehydratedFragment = createFiberFromDehydratedFragment(
362 + suspenseInstance,
363 );
354 - if (suspenseInstance !== null) {
355 - const suspenseState: SuspenseState = {
356 - dehydrated: suspenseInstance,
357 - treeContext: getSuspendedTreeContext(),
358 - retryLane: OffscreenLane,
359 - };
360 - fiber.memoizedState = suspenseState;
361 - // Store the dehydrated fragment as a child fiber.
362 - // This simplifies the code for getHostSibling and deleting nodes,
363 - // since it doesn't have to consider all Suspense boundaries and
364 - // check if they're dehydrated ones or not.
365 - const dehydratedFragment = createFiberFromDehydratedFragment(
366 - suspenseInstance,
367 - );
368 - dehydratedFragment.return = fiber;
369 - fiber.child = dehydratedFragment;
370 - hydrationParentFiber = fiber;
371 - // While a Suspense Instance does have children, we won't step into
372 - // it during the first pass. Instead, we'll reenter it later.
373 - nextHydratableInstance = null;
374 - return true;
375 - }
364 + dehydratedFragment.return = fiber;
365 + fiber.child = dehydratedFragment;
366 + hydrationParentFiber = fiber;
367 + // While a Suspense Instance does have children, we won't step into
368 + // it during the first pass. Instead, we'll reenter it later.
369 + nextHydratableInstance = null;
370 + return true;
371 }
372 return false;
373 }
packages/react-reconciler/src/ReactFiberNewContext.new.js
+2 -9
@@ -42,7 +42,6 @@ import is from 'shared/objectIs';
42 import {createUpdate, ForceUpdate} from './ReactUpdateQueue.new';
43 import {markWorkInProgressReceivedUpdate} from './ReactFiberBeginWork.new';
44 import {
45 - enableSuspenseServerRenderer,
45 enableLazyContextPropagation,
46 enableServerContext,
47 } from 'shared/ReactFeatureFlags';
@@ -295,10 +294,7 @@ function propagateContextChange_eager<T>(
294 } else if (fiber.tag === ContextProvider) {
295 // Don't scan deeper if this is a matching provider
296 nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
298 - } else if (
299 - enableSuspenseServerRenderer &&
300 - fiber.tag === DehydratedFragment
301 - ) {
297 + } else if (fiber.tag === DehydratedFragment) {
298 // If a dehydrated suspense boundary is in this subtree, we don't know
299 // if it will have any context consumers in it. The best we can do is
300 // mark it as having updates.
@@ -425,10 +421,7 @@ function propagateContextChanges<T>(
421 }
422 dep = dependency.next;
423 }
428 - } else if (
429 - enableSuspenseServerRenderer &&
430 - fiber.tag === DehydratedFragment
431 - ) {
424 + } else if (fiber.tag === DehydratedFragment) {
425 // If a dehydrated suspense boundary is in this subtree, we don't know
426 // if it will have any context consumers in it. The best we can do is
427 // mark it as having updates.
packages/react-reconciler/src/ReactFiberNewContext.old.js
+2 -9
@@ -42,7 +42,6 @@ import is from 'shared/objectIs';
42 import {createUpdate, ForceUpdate} from './ReactUpdateQueue.old';
43 import {markWorkInProgressReceivedUpdate} from './ReactFiberBeginWork.old';
44 import {
45 - enableSuspenseServerRenderer,
45 enableLazyContextPropagation,
46 enableServerContext,
47 } from 'shared/ReactFeatureFlags';
@@ -295,10 +294,7 @@ function propagateContextChange_eager<T>(
294 } else if (fiber.tag === ContextProvider) {
295 // Don't scan deeper if this is a matching provider
296 nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
298 - } else if (
299 - enableSuspenseServerRenderer &&
300 - fiber.tag === DehydratedFragment
301 - ) {
297 + } else if (fiber.tag === DehydratedFragment) {
298 // If a dehydrated suspense boundary is in this subtree, we don't know
299 // if it will have any context consumers in it. The best we can do is
300 // mark it as having updates.
@@ -425,10 +421,7 @@ function propagateContextChanges<T>(
421 }
422 dep = dependency.next;
423 }
428 - } else if (
429 - enableSuspenseServerRenderer &&
430 - fiber.tag === DehydratedFragment
431 - ) {
424 + } else if (fiber.tag === DehydratedFragment) {
425 // If a dehydrated suspense boundary is in this subtree, we don't know
426 // if it will have any context consumers in it. The best we can do is
427 // mark it as having updates.
packages/react-reconciler/src/ReactFiberUnwindWork.new.js
+11 -17
@@ -28,11 +28,7 @@ import {
28 } from './ReactWorkTags';
29 import {DidCapture, NoFlags, ShouldCapture} from './ReactFiberFlags';
30 import {NoMode, ProfileMode} from './ReactTypeOfMode';
31 -import {
32 - enableSuspenseServerRenderer,
33 - enableProfilerTimer,
34 - enableCache,
35 -} from 'shared/ReactFeatureFlags';
31 +import {enableProfilerTimer, enableCache} from 'shared/ReactFeatureFlags';
32
33 import {popHostContainer, popHostContext} from './ReactFiberHostContext.new';
34 import {popSuspenseContext} from './ReactFiberSuspenseContext.new';
@@ -108,20 +104,18 @@ function unwindWork(
104 }
105 case SuspenseComponent: {
106 popSuspenseContext(workInProgress);
111 - if (enableSuspenseServerRenderer) {
112 - const suspenseState: null | SuspenseState =
113 - workInProgress.memoizedState;
114 - if (suspenseState !== null && suspenseState.dehydrated !== null) {
115 - if (workInProgress.alternate === null) {
116 - throw new Error(
117 - 'Threw in newly mounted dehydrated component. This is likely a bug in ' +
118 - 'React. Please file an issue.',
119 - );
120 - }
121 -
122 - resetHydrationState();
107 + const suspenseState: null | SuspenseState = workInProgress.memoizedState;
108 + if (suspenseState !== null && suspenseState.dehydrated !== null) {
109 + if (workInProgress.alternate === null) {
110 + throw new Error(
111 + 'Threw in newly mounted dehydrated component. This is likely a bug in ' +
112 + 'React. Please file an issue.',
113 + );
114 }
115 +
116 + resetHydrationState();
117 }
118 +
119 const flags = workInProgress.flags;
120 if (flags & ShouldCapture) {
121 workInProgress.flags = (flags & ~ShouldCapture) | DidCapture;
packages/react-reconciler/src/ReactFiberUnwindWork.old.js
+11 -17
@@ -28,11 +28,7 @@ import {
28 } from './ReactWorkTags';
29 import {DidCapture, NoFlags, ShouldCapture} from './ReactFiberFlags';
30 import {NoMode, ProfileMode} from './ReactTypeOfMode';
31 -import {
32 - enableSuspenseServerRenderer,
33 - enableProfilerTimer,
34 - enableCache,
35 -} from 'shared/ReactFeatureFlags';
31 +import {enableProfilerTimer, enableCache} from 'shared/ReactFeatureFlags';
32
33 import {popHostContainer, popHostContext} from './ReactFiberHostContext.old';
34 import {popSuspenseContext} from './ReactFiberSuspenseContext.old';
@@ -108,20 +104,18 @@ function unwindWork(
104 }
105 case SuspenseComponent: {
106 popSuspenseContext(workInProgress);
111 - if (enableSuspenseServerRenderer) {
112 - const suspenseState: null | SuspenseState =
113 - workInProgress.memoizedState;
114 - if (suspenseState !== null && suspenseState.dehydrated !== null) {
115 - if (workInProgress.alternate === null) {
116 - throw new Error(
117 - 'Threw in newly mounted dehydrated component. This is likely a bug in ' +
118 - 'React. Please file an issue.',
119 - );
120 - }
121 -
122 - resetHydrationState();
107 + const suspenseState: null | SuspenseState = workInProgress.memoizedState;
108 + if (suspenseState !== null && suspenseState.dehydrated !== null) {
109 + if (workInProgress.alternate === null) {
110 + throw new Error(
111 + 'Threw in newly mounted dehydrated component. This is likely a bug in ' +
112 + 'React. Please file an issue.',
113 + );
114 }
115 +
116 + resetHydrationState();
117 }
118 +
119 const flags = workInProgress.flags;
120 if (flags & ShouldCapture) {
121 workInProgress.flags = (flags & ~ShouldCapture) | DidCapture;
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+16 -21
@@ -23,7 +23,6 @@ import type {
23
24 import {
25 warnAboutDeprecatedLifecycles,
26 - enableSuspenseServerRenderer,
26 replayFailedUnitOfWorkWithInvokeGuardedCallback,
27 enableCreateEventHandleAPI,
28 enableProfilerTimer,
@@ -2776,26 +2775,22 @@ export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {
2775 export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) {
2776 let retryLane = NoLane; // Default
2777 let retryCache: WeakSet<Wakeable> | Set<Wakeable> | null;
2779 - if (enableSuspenseServerRenderer) {
2780 - switch (boundaryFiber.tag) {
2781 - case SuspenseComponent:
2782 - retryCache = boundaryFiber.stateNode;
2783 - const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
2784 - if (suspenseState !== null) {
2785 - retryLane = suspenseState.retryLane;
2786 - }
2787 - break;
2788 - case SuspenseListComponent:
2789 - retryCache = boundaryFiber.stateNode;
2790 - break;
2791 - default:
2792 - throw new Error(
2793 - 'Pinged unknown suspense boundary type. ' +
2794 - 'This is probably a bug in React.',
2795 - );
2796 - }
2797 - } else {
2798 - retryCache = boundaryFiber.stateNode;
2778 + switch (boundaryFiber.tag) {
2779 + case SuspenseComponent:
2780 + retryCache = boundaryFiber.stateNode;
2781 + const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
2782 + if (suspenseState !== null) {
2783 + retryLane = suspenseState.retryLane;
2784 + }
2785 + break;
2786 + case SuspenseListComponent:
2787 + retryCache = boundaryFiber.stateNode;
2788 + break;
2789 + default:
2790 + throw new Error(
2791 + 'Pinged unknown suspense boundary type. ' +
2792 + 'This is probably a bug in React.',
2793 + );
2794 }
2795
2796 if (retryCache !== null) {
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+16 -21
@@ -23,7 +23,6 @@ import type {
23
24 import {
25 warnAboutDeprecatedLifecycles,
26 - enableSuspenseServerRenderer,
26 replayFailedUnitOfWorkWithInvokeGuardedCallback,
27 enableCreateEventHandleAPI,
28 enableProfilerTimer,
@@ -2776,26 +2775,22 @@ export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {
2775 export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) {
2776 let retryLane = NoLane; // Default
2777 let retryCache: WeakSet<Wakeable> | Set<Wakeable> | null;
2779 - if (enableSuspenseServerRenderer) {
2780 - switch (boundaryFiber.tag) {
2781 - case SuspenseComponent:
2782 - retryCache = boundaryFiber.stateNode;
2783 - const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
2784 - if (suspenseState !== null) {
2785 - retryLane = suspenseState.retryLane;
2786 - }
2787 - break;
2788 - case SuspenseListComponent:
2789 - retryCache = boundaryFiber.stateNode;
2790 - break;
2791 - default:
2792 - throw new Error(
2793 - 'Pinged unknown suspense boundary type. ' +
2794 - 'This is probably a bug in React.',
2795 - );
2796 - }
2797 - } else {
2798 - retryCache = boundaryFiber.stateNode;
2778 + switch (boundaryFiber.tag) {
2779 + case SuspenseComponent:
2780 + retryCache = boundaryFiber.stateNode;
2781 + const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
2782 + if (suspenseState !== null) {
2783 + retryLane = suspenseState.retryLane;
2784 + }
2785 + break;
2786 + case SuspenseListComponent:
2787 + retryCache = boundaryFiber.stateNode;
2788 + break;
2789 + default:
2790 + throw new Error(
2791 + 'Pinged unknown suspense boundary type. ' +
2792 + 'This is probably a bug in React.',
2793 + );
2794 }
2795
2796 if (retryCache !== null) {
packages/shared/ReactFeatureFlags.js
-1
@@ -13,7 +13,6 @@
13 // Flags that can likely be deleted or landed without consequences
14 // -----------------------------------------------------------------------------
15
16 -export const enableSuspenseServerRenderer = true;
16 export const enableSelectiveHydration = true;
17 export const warnAboutDeprecatedLifecycles = true;
18 export const enableComponentStackLocations = true;
packages/shared/forks/ReactFeatureFlags.native-fb.js
-1
@@ -26,7 +26,6 @@ export const enableProfilerCommitHooks = __PROFILE__;
26 export const enableProfilerNestedUpdatePhase = __PROFILE__;
27 export const enableProfilerNestedUpdateScheduledHook = false;
28 export const enableUpdaterTracking = __PROFILE__;
29 -export const enableSuspenseServerRenderer = false;
29 export const enableSelectiveHydration = false;
30 export const enableCache = false;
31 export const enableCacheElement = true;
packages/shared/forks/ReactFeatureFlags.native-oss.js
-1
@@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__;
20 export const enableProfilerNestedUpdatePhase = __PROFILE__;
21 export const enableProfilerNestedUpdateScheduledHook = false;
22 export const enableUpdaterTracking = __PROFILE__;
23 -export const enableSuspenseServerRenderer = false;
23 export const enableSelectiveHydration = false;
24 export const enableCache = false;
25 export const enableCacheElement = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-1
@@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__;
20 export const enableProfilerNestedUpdatePhase = __PROFILE__;
21 export const enableProfilerNestedUpdateScheduledHook = false;
22 export const enableUpdaterTracking = false;
23 -export const enableSuspenseServerRenderer = false;
23 export const enableSelectiveHydration = false;
24 export const enableCache = __EXPERIMENTAL__;
25 export const enableCacheElement = __EXPERIMENTAL__;
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
-1
@@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__;
20 export const enableProfilerNestedUpdatePhase = __PROFILE__;
21 export const enableProfilerNestedUpdateScheduledHook = false;
22 export const enableUpdaterTracking = false;
23 -export const enableSuspenseServerRenderer = false;
23 export const enableSelectiveHydration = false;
24 export const enableCache = true;
25 export const enableCacheElement = true;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-1
@@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__;
20 export const enableProfilerNestedUpdatePhase = __PROFILE__;
21 export const enableProfilerNestedUpdateScheduledHook = false;
22 export const enableUpdaterTracking = false;
23 -export const enableSuspenseServerRenderer = false;
23 export const enableSelectiveHydration = false;
24 export const enableCache = true;
25 export const enableCacheElement = true;
packages/shared/forks/ReactFeatureFlags.testing.js
-1
@@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = __PROFILE__;
20 export const enableProfilerNestedUpdatePhase = __PROFILE__;
21 export const enableProfilerNestedUpdateScheduledHook = false;
22 export const enableUpdaterTracking = false;
23 -export const enableSuspenseServerRenderer = false;
23 export const enableSelectiveHydration = false;
24 export const enableCache = __EXPERIMENTAL__;
25 export const enableCacheElement = __EXPERIMENTAL__;
packages/shared/forks/ReactFeatureFlags.testing.www.js
-1
@@ -20,7 +20,6 @@ export const enableProfilerCommitHooks = false;
20 export const enableProfilerNestedUpdatePhase = false;
21 export const enableProfilerNestedUpdateScheduledHook = false;
22 export const enableUpdaterTracking = false;
23 -export const enableSuspenseServerRenderer = true;
23 export const enableSelectiveHydration = true;
24 export const enableCache = true;
25 export const enableCacheElement = true;
packages/shared/forks/ReactFeatureFlags.www.js
-1
@@ -67,7 +67,6 @@ export const disableLegacyContext = __EXPERIMENTAL__;
67 export const warnAboutStringRefs = false;
68 export const warnAboutDefaultPropsOnFunctionComponents = false;
69 export const enableGetInspectorDataForInstanceInProduction = false;
70 -export const enableSuspenseServerRenderer = true;
70 export const enableSelectiveHydration = true;
71
72 export const enableCache = true;