@samitouri / QOS-React-2 / commits / 3a60844a0f

Update error message for suspending at sync priority (#23361)

Instead of adding a new Suspense boundary, the default recommendation is to wrap the suspending update with startTransition.

Andrew Clark committed Feb 24, 2022 at 21:02 UTC 3a60844a0f3449d7e6d208e31df44c5ba3466e38
6 files changed +19 -26
packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js
+2 -2
@@ -187,7 +187,7 @@ describe('ReactDOMServerSuspense', () => {
187 1,
188 );
189 },
190 - 'Add a <Suspense fallback=...> component higher in the tree',
190 + 'A component suspended while responding to synchronous input.',
191 );
192
193 itThrowsWhenRendering(
@@ -200,7 +200,7 @@ describe('ReactDOMServerSuspense', () => {
200 1,
201 );
202 },
203 - 'Add a <Suspense fallback=...> component higher in the tree',
203 + 'A component suspended while responding to synchronous input.',
204 );
205 }
206
packages/react-dom/src/server/ReactDOMLegacyServerBrowser.js
+6 -4
@@ -78,11 +78,13 @@ function renderToStringImpl(
78 }
79
80 if (!readyToStream) {
81 + // Note: This error message is the one we use on the client. It doesn't
82 + // really make sense here. But this is the legacy server renderer, anyway.
83 + // We're going to delete it soon.
84 throw new Error(
82 - 'A React component suspended while rendering, but no fallback UI was specified.\n' +
83 - '\n' +
84 - 'Add a <Suspense fallback=...> component higher in the tree to ' +
85 - 'provide a loading indicator or placeholder to display.',
85 + 'A component suspended while responding to synchronous input. This ' +
86 + 'will cause the UI to be replaced with a loading indicator. To fix, ' +
87 + 'updates that suspend should be wrapped with startTransition.',
88 );
89 }
90
packages/react-reconciler/src/ReactFiberThrow.new.js
+4 -8
@@ -499,15 +499,11 @@ function throwException(
499 // This is a sync/discrete update. We treat this case like an error
500 // because discrete renders are expected to produce a complete tree
501 // synchronously to maintain consistency with external state.
502 -
503 - // TODO: We should never call getComponentNameFromFiber in production.
504 - // Log a warning or something to prevent us from accidentally bundling it.
502 const uncaughtSuspenseError = new Error(
506 - (getComponentNameFromFiber(sourceFiber) || 'A React component') +
507 - ' suspended while rendering, but no fallback UI was specified.\n' +
508 - '\n' +
509 - 'Add a <Suspense fallback=...> component higher in the tree to ' +
510 - 'provide a loading indicator or placeholder to display.',
503 + 'A component suspended while responding to synchronous input. This ' +
504 + 'will cause the UI to be replaced with a loading indicator. To ' +
505 + 'fix, updates that suspend should be wrapped ' +
506 + 'with startTransition.',
507 );
508
509 // If we're outside a transition, fall through to the regular error path.
packages/react-reconciler/src/ReactFiberThrow.old.js
+4 -8
@@ -499,15 +499,11 @@ function throwException(
499 // This is a sync/discrete update. We treat this case like an error
500 // because discrete renders are expected to produce a complete tree
501 // synchronously to maintain consistency with external state.
502 -
503 - // TODO: We should never call getComponentNameFromFiber in production.
504 - // Log a warning or something to prevent us from accidentally bundling it.
502 const uncaughtSuspenseError = new Error(
506 - (getComponentNameFromFiber(sourceFiber) || 'A React component') +
507 - ' suspended while rendering, but no fallback UI was specified.\n' +
508 - '\n' +
509 - 'Add a <Suspense fallback=...> component higher in the tree to ' +
510 - 'provide a loading indicator or placeholder to display.',
503 + 'A component suspended while responding to synchronous input. This ' +
504 + 'will cause the UI to be replaced with a loading indicator. To ' +
505 + 'fix, updates that suspend should be wrapped ' +
506 + 'with startTransition.',
507 );
508
509 // If we're outside a transition, fall through to the regular error path.
packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
+1 -3
@@ -1011,9 +1011,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1011 ReactNoop.flushSync(() => {
1012 ReactNoop.render(<AsyncText text="Async" />);
1013 });
1014 - }).toThrow(
1015 - 'AsyncText suspended while rendering, but no fallback UI was specified.',
1016 - );
1014 + }).toThrow('A component suspended while responding to synchronous input.');
1015 });
1016
1017 // @gate enableCache
scripts/error-codes/codes.json
+2 -1
@@ -409,5 +409,6 @@
409 "421": "There was an error while hydrating this Suspense boundary. Switched to client rendering.",
410 "422": "There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.",
411 "423": "This root received an early update, before anything was able hydrate. Switched the entire root to client rendering.",
412 - "424": "Text content does not match server-rendered HTML."
412 + "424": "Text content does not match server-rendered HTML.",
413 + "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."
414 }