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;