diff --git a/compat/src/suspense.js b/compat/src/suspense.js index 3bb60c9eb0..6d5333a3b7 100644 --- a/compat/src/suspense.js +++ b/compat/src/suspense.js @@ -243,18 +243,23 @@ export function suspended(vnode) { export function lazy(loader) { let prom; - let component; + let component = null; let error; + let resolved; function Lazy(props) { if (!prom) { prom = loader(); prom.then( exports => { - component = exports.default || exports; + if (exports) { + component = exports.default || exports; + } + resolved = true; }, e => { error = e; + resolved = true; } ); } @@ -263,11 +268,11 @@ export function lazy(loader) { throw error; } - if (!component) { + if (!resolved) { throw prom; } - return createElement(component, props); + return component ? createElement(component, props) : null; } Lazy.displayName = 'Lazy'; diff --git a/compat/test/browser/suspense.test.js b/compat/test/browser/suspense.test.js index d18dc8104f..2998d80f30 100644 --- a/compat/test/browser/suspense.test.js +++ b/compat/test/browser/suspense.test.js @@ -105,6 +105,59 @@ describe('suspense', () => { }); }); + it('should handle lazy component that rejects without returning a component', async () => { + const errorSpy = sinon.spy(); + let renderCount = 0; + + let resolve; + function fakeImport() { + const p = new Promise((_, reject) => { + resolve = () => { + reject(new Error('import failed')); + return p; + }; + }); + return p; + } + + const SomeComponent = lazy(() => + fakeImport().catch(e => { + console.log('caught', e); + errorSpy(e); + }) + ); + + const App = () => { + renderCount++; + if (renderCount > 5) { + throw new Error('Infinite loop detected!'); + } + + console.log('RENDER COUNT', renderCount); + return ( +