Skip to content

Commit 02a280b

Browse files
committed
Temporarily disable suspending during work loop
`use` has an optimization where in some cases it can suspend the work loop during the render phase until the data has resolved, rather than unwind the stack and lose context. However, the current implementation is not compatible with sibling prerendering. So I've temporarily disabled it until the sibling prerendering has been refactored. We will add it back in a later step.
1 parent 9dcd368 commit 02a280b

File tree

3 files changed

+21
-0
lines changed

3 files changed

+21
-0
lines changed

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
disableLegacyMode,
4444
disableDefaultPropsExceptForClasses,
4545
disableStringRefs,
46+
enableSiblingPrerendering,
4647
} from 'shared/ReactFeatureFlags';
4748
import ReactSharedInternals from 'shared/ReactSharedInternals';
4849
import is from 'shared/objectIs';
@@ -1700,6 +1701,10 @@ function handleThrow(root: FiberRoot, thrownValue: any): void {
17001701
// deprecate the old API in favor of `use`.
17011702
thrownValue = getSuspendedThenable();
17021703
workInProgressSuspendedReason =
1704+
// TODO: Suspending the work loop during the render phase is
1705+
// currently not compatible with sibling prerendering. We will add
1706+
// this optimization back in a later step.
1707+
!enableSiblingPrerendering &&
17031708
shouldRemainOnPreviousScreen() &&
17041709
// Check if there are other pending updates that might possibly unblock this
17051710
// component from suspending. This mirrors the check in

packages/react-reconciler/src/__tests__/ReactUse-test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ describe('ReactUse', () => {
558558
}
559559
});
560560

561+
// @gate enableSuspendingDuringWorkLoop
561562
it('during a transition, can unwrap async operations even if nothing is cached', async () => {
562563
function App() {
563564
return <Text text={use(getAsyncText('Async'))} />;
@@ -593,6 +594,7 @@ describe('ReactUse', () => {
593594
expect(root).toMatchRenderedOutput('Async');
594595
});
595596

597+
// @gate enableSuspendingDuringWorkLoop
596598
it("does not prevent a Suspense fallback from showing if it's a new boundary, even during a transition", async () => {
597599
function App() {
598600
return <Text text={use(getAsyncText('Async'))} />;
@@ -635,6 +637,7 @@ describe('ReactUse', () => {
635637
expect(root).toMatchRenderedOutput('Async');
636638
});
637639

640+
// @gate enableSuspendingDuringWorkLoop
638641
it('when waiting for data to resolve, a fresh update will trigger a restart', async () => {
639642
function App() {
640643
return <Text text={use(getAsyncText('Will never resolve'))} />;
@@ -666,6 +669,7 @@ describe('ReactUse', () => {
666669
assertLog(['Something different']);
667670
});
668671

672+
// @gate enableSuspendingDuringWorkLoop
669673
it('when waiting for data to resolve, an update on a different root does not cause work to be dropped', async () => {
670674
const promise = getAsyncText('Hi');
671675

@@ -708,6 +712,7 @@ describe('ReactUse', () => {
708712
expect(root1).toMatchRenderedOutput('Hi');
709713
});
710714

715+
// @gate enableSuspendingDuringWorkLoop
711716
it('while suspended, hooks cannot be called (i.e. current dispatcher is unset correctly)', async () => {
712717
function App() {
713718
return <Text text={use(getAsyncText('Will never resolve'))} />;
@@ -845,6 +850,7 @@ describe('ReactUse', () => {
845850
expect(root).toMatchRenderedOutput('(empty)');
846851
});
847852

853+
// @gate enableSuspendingDuringWorkLoop
848854
it('when replaying a suspended component, reuses the hooks computed during the previous attempt (Memo)', async () => {
849855
function ExcitingText({text}) {
850856
// This computes the uppercased version of some text. Pretend it's an
@@ -894,6 +900,7 @@ describe('ReactUse', () => {
894900
]);
895901
});
896902

903+
// @gate enableSuspendingDuringWorkLoop
897904
it('when replaying a suspended component, reuses the hooks computed during the previous attempt (State)', async () => {
898905
let _setFruit;
899906
let _setVegetable;
@@ -950,6 +957,7 @@ describe('ReactUse', () => {
950957
expect(root).toMatchRenderedOutput('banana dill');
951958
});
952959

960+
// @gate enableSuspendingDuringWorkLoop
953961
it('when replaying a suspended component, reuses the hooks computed during the previous attempt (DebugValue+State)', async () => {
954962
// Make sure we don't get a Hook mismatch warning on updates if there were non-stateful Hooks before the use().
955963
let _setLawyer;
@@ -991,6 +999,7 @@ describe('ReactUse', () => {
991999
expect(root).toMatchRenderedOutput('aguacate avocat');
9921000
});
9931001

1002+
// @gate enableSuspendingDuringWorkLoop
9941003
it(
9951004
'wrap an async function with useMemo to skip running the function ' +
9961005
'twice when loading new data',
@@ -1073,6 +1082,7 @@ describe('ReactUse', () => {
10731082
expect(root).toMatchRenderedOutput('ABC');
10741083
});
10751084

1085+
// @gate enableSuspendingDuringWorkLoop
10761086
it('load multiple nested Suspense boundaries (uncached requests)', async () => {
10771087
// This the same as the previous test, except the requests are not cached.
10781088
// The tree should still eventually resolve, despite the
@@ -1196,6 +1206,7 @@ describe('ReactUse', () => {
11961206
expect(root).toMatchRenderedOutput('Hi');
11971207
});
11981208

1209+
// @gate enableSuspendingDuringWorkLoop
11991210
it('basic async component', async () => {
12001211
async function App() {
12011212
await getAsyncText('Hi');
@@ -1220,6 +1231,7 @@ describe('ReactUse', () => {
12201231
expect(root).toMatchRenderedOutput('Hi');
12211232
});
12221233

1234+
// @gate enableSuspendingDuringWorkLoop
12231235
it('async child of a non-function component (e.g. a class)', async () => {
12241236
class App extends React.Component {
12251237
async render() {

scripts/jest/TestFlags.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ function getTestFlags() {
8383
enableActivity: releaseChannel === 'experimental' || www || xplat,
8484
enableSuspenseList: releaseChannel === 'experimental' || www || xplat,
8585
enableLegacyHidden: www,
86+
// TODO: Suspending the work loop during the render phase is currently
87+
// not compatible with sibling prerendering. We will add this optimization
88+
// back in a later step.
89+
enableSuspendingDuringWorkLoop: !featureFlags.enableSiblingPrerendering,
8690

8791
// This flag is used to determine whether we should run Fizz tests using
8892
// the external runtime or the inline script runtime.

0 commit comments

Comments
 (0)