From 10a7a5b5ced683125d68584a78084faac3197846 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Sat, 19 Jan 2019 00:42:43 +0000 Subject: [PATCH] Fix synchronous thenable rejection (#14633) * Fix handling of sync rejection Reverts #14632 and adds a regression test. * Handle rejection synchronously too Fewer footguns and seems like nicer behavior anyway. --- .../src/ReactFiberLazyComponent.js | 9 ++++-- .../src/__tests__/ReactLazy-test.internal.js | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberLazyComponent.js b/packages/react-reconciler/src/ReactFiberLazyComponent.js index 07fd7a70762de..1db5ecd35cab2 100644 --- a/packages/react-reconciler/src/ReactFiberLazyComponent.js +++ b/packages/react-reconciler/src/ReactFiberLazyComponent.js @@ -73,9 +73,12 @@ export function readLazyComponentType(lazyComponent: LazyComponent): T { } }, ); - // Check if it resolved synchronously - if (lazyComponent._status === Resolved) { - return lazyComponent._result; + // Handle synchronous thenables. + switch (lazyComponent._status) { + case Resolved: + return lazyComponent._result; + case Rejected: + throw lazyComponent._result; } lazyComponent._result = thenable; throw thenable; diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index 8fb4210f92923..4ce785815447b 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -78,6 +78,36 @@ describe('ReactLazy', () => { expect(root).toMatchRenderedOutput('Hi'); }); + it('can reject synchronously without suspending', async () => { + const LazyText = lazy(() => ({ + then(resolve, reject) { + reject(new Error('oh no')); + }, + })); + + class ErrorBoundary extends React.Component { + state = {}; + static getDerivedStateFromError(error) { + return {message: error.message}; + } + render() { + return this.state.message + ? `Error: ${this.state.message}` + : this.props.children; + } + } + + const root = ReactTestRenderer.create( + + }> + + + , + ); + expect(ReactTestRenderer).toHaveYielded([]); + expect(root).toMatchRenderedOutput('Error: oh no'); + }); + it('multiple lazy components', async () => { function Foo() { return ;