Tweak error message for missing fallback (#14068)
Sophie Alpert committed
Nov 1, 2018 at 22:45 UTC
c84b9bf828c38e0b24042ebb9cd859292146a6fb
4 files changed
+26
-4
packages/react-reconciler/src/ReactCurrentFiber.js
+2
@@ -17,6 +17,7 @@ import {
17
HostComponent,
18
Mode,
19
LazyComponent,
20
+ SuspenseComponent,
21
} from 'shared/ReactWorkTags';
22
import describeComponentFrame from 'shared/describeComponentFrame';
23
import getComponentName from 'shared/getComponentName';
@@ -33,6 +34,7 @@ function describeFiber(fiber: Fiber): string {
34
case ClassComponent:
35
case HostComponent:
36
case Mode:
37
+ case SuspenseComponent:
38
const owner = fiber._debugOwner;
39
const source = fiber._debugSource;
40
const name = getComponentName(fiber.type);
packages/react-reconciler/src/ReactFiberUnwindWork.js
+8
-1
@@ -46,6 +46,7 @@ import {
46
CaptureUpdate,
47
} from './ReactUpdateQueue';
48
import {logError} from './ReactFiberCommitWork';
49
+import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
50
import {popHostContainer, popHostContext} from './ReactFiberHostContext';
51
import {
52
isContextProvider as isLegacyContextProvider,
@@ -315,8 +316,14 @@ function throwException(
316
workInProgress = workInProgress.return;
317
} while (workInProgress !== null);
318
// No boundary was found. Fallthrough to error mode.
319
+ // TODO: Use invariant so the message is stripped in prod?
320
value = new Error(
319
- 'An update was suspended, but no placeholder UI was provided.',
321
+ (getComponentName(sourceFiber.type) || 'A React component') +
322
+ ' suspended while rendering, but no fallback UI was specified.\n' +
323
+ '\n' +
324
+ 'Add a <Suspense fallback=...> component higher in the tree to ' +
325
+ 'provide a loading indicator or placeholder to display.' +
326
+ getStackByFiberInDevAndProd(sourceFiber),
327
);
328
}
329
packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
+13
-2
@@ -312,8 +312,19 @@ describe('ReactSuspense', () => {
312
},
313
);
314
315
- expect(root).toFlushAndThrow(
316
- 'An update was suspended, but no placeholder UI was provided.',
315
+ let err;
316
+ try {
317
+ root.unstable_flushAll();
318
+ } catch (e) {
319
+ err = e;
320
+ }
321
+ expect(err.message.replace(/at .+?:\d+/g, 'at **')).toBe(
322
+ 'AsyncText suspended while rendering, but no fallback UI was specified.\n' +
323
+ '\n' +
324
+ 'Add a <Suspense fallback=...> component higher in the tree to provide ' +
325
+ 'a loading indicator or placeholder to display.\n' +
326
+ (__DEV__ ? ' in AsyncText (at **)\n' : ' in AsyncText\n') +
327
+ (__DEV__ ? ' in Suspense (at **)' : ' in Suspense'),
328
);
329
expect(ReactTestRenderer).toHaveYielded(['Suspend! [Hi]', 'Suspend! [Hi]']);
330
});
packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js
+3
-1
@@ -652,7 +652,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
652
it('throws a helpful error when an update is suspends without a placeholder', () => {
653
expect(() => {
654
ReactNoop.flushSync(() => ReactNoop.render(<AsyncText text="Async" />));
655
- }).toThrow('An update was suspended, but no placeholder UI was provided.');
655
+ }).toThrow(
656
+ 'AsyncText suspended while rendering, but no fallback UI was specified.',
657
+ );
658
});
659
660
it('a Suspense component correctly handles more than one suspended child', async () => {