Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -1891,11 +1891,13 @@ function mountLazyComponent(
}
}

const loggedComponent = getComponentNameFromType(Component) || String(Component);

// This message intentionally doesn't mention ForwardRef or MemoComponent
// because the fact that it's a separate type of work is an
// implementation detail.
throw new Error(
`Element type is invalid. Received a promise that resolves to: ${Component}. ` +
`Element type is invalid. Received a promise that resolves to: ${loggedComponent}. ` +
`Lazy element type must resolve to a class or function.${hint}`,
);
}
Expand Down
26 changes: 26 additions & 0 deletions packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,32 @@ describe('ReactLazy', () => {
);
});

it('throws with a useful error when wrapping fragment with lazy()', async () => {
const BadLazy = lazy(() => fakeImport(React.Fragment));

const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<BadLazy />
</Suspense>,
{
unstable_isConcurrent: true,
},
);

await waitForAll(['Loading...']);

await resolveFakeImport(React.Fragment);
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<BadLazy />
</Suspense>,
);
await waitForThrow(
'Element type is invalid. Received a promise that resolves to: Fragment. ' +
'Lazy element type must resolve to a class or function.',
);
});

it('throws with a useful error when wrapping lazy() multiple times', async () => {
const Lazy1 = lazy(() => fakeImport(Text));
const Lazy2 = lazy(() => fakeImport(Lazy1));
Expand Down