Skip to content

Commit

Permalink
Update error message for suspending at sync priority (#23361)
Browse files Browse the repository at this point in the history
Instead of adding a new Suspense boundary, the default recommendation
is to wrap the suspending update with startTransition.
  • Loading branch information
acdlite authored Feb 25, 2022
1 parent 8d0d0e9 commit 3a60844
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ describe('ReactDOMServerSuspense', () => {
1,
);
},
'Add a <Suspense fallback=...> component higher in the tree',
'A component suspended while responding to synchronous input.',
);

itThrowsWhenRendering(
Expand All @@ -200,7 +200,7 @@ describe('ReactDOMServerSuspense', () => {
1,
);
},
'Add a <Suspense fallback=...> component higher in the tree',
'A component suspended while responding to synchronous input.',
);
}

Expand Down
10 changes: 6 additions & 4 deletions packages/react-dom/src/server/ReactDOMLegacyServerBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,13 @@ function renderToStringImpl(
}

if (!readyToStream) {
// Note: This error message is the one we use on the client. It doesn't
// really make sense here. But this is the legacy server renderer, anyway.
// We're going to delete it soon.
throw new Error(
'A React component suspended while rendering, but no fallback UI was specified.\n' +
'\n' +
'Add a <Suspense fallback=...> component higher in the tree to ' +
'provide a loading indicator or placeholder to display.',
'A component suspended while responding to synchronous input. This ' +
'will cause the UI to be replaced with a loading indicator. To fix, ' +
'updates that suspend should be wrapped with startTransition.',
);
}

Expand Down
12 changes: 4 additions & 8 deletions packages/react-reconciler/src/ReactFiberThrow.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,11 @@ function throwException(
// This is a sync/discrete update. We treat this case like an error
// because discrete renders are expected to produce a complete tree
// synchronously to maintain consistency with external state.

// TODO: We should never call getComponentNameFromFiber in production.
// Log a warning or something to prevent us from accidentally bundling it.
const uncaughtSuspenseError = new Error(
(getComponentNameFromFiber(sourceFiber) || 'A React component') +
' suspended while rendering, but no fallback UI was specified.\n' +
'\n' +
'Add a <Suspense fallback=...> component higher in the tree to ' +
'provide a loading indicator or placeholder to display.',
'A component suspended while responding to synchronous input. This ' +
'will cause the UI to be replaced with a loading indicator. To ' +
'fix, updates that suspend should be wrapped ' +
'with startTransition.',
);

// If we're outside a transition, fall through to the regular error path.
Expand Down
12 changes: 4 additions & 8 deletions packages/react-reconciler/src/ReactFiberThrow.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,11 @@ function throwException(
// This is a sync/discrete update. We treat this case like an error
// because discrete renders are expected to produce a complete tree
// synchronously to maintain consistency with external state.

// TODO: We should never call getComponentNameFromFiber in production.
// Log a warning or something to prevent us from accidentally bundling it.
const uncaughtSuspenseError = new Error(
(getComponentNameFromFiber(sourceFiber) || 'A React component') +
' suspended while rendering, but no fallback UI was specified.\n' +
'\n' +
'Add a <Suspense fallback=...> component higher in the tree to ' +
'provide a loading indicator or placeholder to display.',
'A component suspended while responding to synchronous input. This ' +
'will cause the UI to be replaced with a loading indicator. To ' +
'fix, updates that suspend should be wrapped ' +
'with startTransition.',
);

// If we're outside a transition, fall through to the regular error path.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1011,9 +1011,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
ReactNoop.flushSync(() => {
ReactNoop.render(<AsyncText text="Async" />);
});
}).toThrow(
'AsyncText suspended while rendering, but no fallback UI was specified.',
);
}).toThrow('A component suspended while responding to synchronous input.');
});

// @gate enableCache
Expand Down
3 changes: 2 additions & 1 deletion scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -409,5 +409,6 @@
"421": "There was an error while hydrating this Suspense boundary. Switched to client rendering.",
"422": "There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.",
"423": "This root received an early update, before anything was able hydrate. Switched the entire root to client rendering.",
"424": "Text content does not match server-rendered HTML."
"424": "Text content does not match server-rendered HTML.",
"425": "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition."
}

0 comments on commit 3a60844

Please sign in to comment.