From e08f2e66e9e1a11522c0aa4338ae5d37c41195c0 Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Thu, 18 Jul 2024 11:04:28 +0100 Subject: [PATCH 1/6] Log proper error when trying to render a lazy fragment Ammend test --- .../src/ReactFiberBeginWork.js | 5 +++- .../src/__tests__/ReactLazy-test.internal.js | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 98a89e018da97..76876e023324c 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -124,6 +124,7 @@ import { REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE, getIteratorFn, + REACT_FRAGMENT_TYPE, } from 'shared/ReactSymbols'; import { getCurrentFiberOwnerNameInDevOrNull, @@ -1891,11 +1892,13 @@ function mountLazyComponent( } } + const loggedComponent = Component === REACT_FRAGMENT_TYPE ? '' : 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}`, ); } diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index 644913a15fd9f..f1764dc322cc1 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -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( + }> + + , + { + unstable_isConcurrent: true, + }, + ); + + await waitForAll(['Loading...']); + + await resolveFakeImport(React.Fragment); + root.update( + }> + + , + ); + await waitForThrow( + 'Element type is invalid. Received a promise that resolves to: . ' + + '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)); From 55ee91c25545eeb55f3dd340ad56e1c889f59a4b Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Tue, 23 Jul 2024 10:05:59 +0100 Subject: [PATCH 2/6] Use getComponentNameFromType Co-authored-by: Sebastian Silbermann --- packages/react-reconciler/src/ReactFiberBeginWork.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 76876e023324c..7b7a9d965c4fa 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -1892,7 +1892,7 @@ function mountLazyComponent( } } - const loggedComponent = Component === REACT_FRAGMENT_TYPE ? '' : Component; + 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 From 88cb77d21424ae04f6b12d65246032cdc1114035 Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Tue, 23 Jul 2024 10:06:25 +0100 Subject: [PATCH 3/6] Remove unused import --- packages/react-reconciler/src/ReactFiberBeginWork.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 7b7a9d965c4fa..97bd435c607c8 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -124,7 +124,6 @@ import { REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE, getIteratorFn, - REACT_FRAGMENT_TYPE, } from 'shared/ReactSymbols'; import { getCurrentFiberOwnerNameInDevOrNull, From 9acb2110868e35fb787e691352a11d7ffdadf3ff Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Tue, 23 Jul 2024 10:07:41 +0100 Subject: [PATCH 4/6] Update test --- .../react-reconciler/src/__tests__/ReactLazy-test.internal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index f1764dc322cc1..259b780038fc6 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -778,7 +778,7 @@ describe('ReactLazy', () => { , ); await waitForThrow( - 'Element type is invalid. Received a promise that resolves to: . ' + + 'Element type is invalid. Received a promise that resolves to: Fragment. ' + 'Lazy element type must resolve to a class or function.', ); }); From bdd623fc08e0d1498ebdcea1a1961fcdefbf7fbb Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Tue, 23 Jul 2024 17:04:35 +0100 Subject: [PATCH 5/6] Ignore string coercion lint --- packages/react-reconciler/src/ReactFiberBeginWork.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 97bd435c607c8..2c722c74eaf9b 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -1891,7 +1891,10 @@ function mountLazyComponent( } } - const loggedComponent = getComponentNameFromType(Component) || String(Component); + const loggedComponent = + getComponentNameFromType(Component) || + // eslint-disable-next-line react-internal/safe-string-coercion + '' + Component; // This message intentionally doesn't mention ForwardRef or MemoComponent // because the fact that it's a separate type of work is an From 228669ea61ebd1245d23ec3f5e7a07e664feeecf Mon Sep 17 00:00:00 2001 From: eps1lon Date: Tue, 23 Jul 2024 18:45:32 +0200 Subject: [PATCH 6/6] Keep original behavior if `Component` isn't a Component --- packages/react-reconciler/src/ReactFiberBeginWork.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 2c722c74eaf9b..eae5dc5a964ff 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -1891,10 +1891,7 @@ function mountLazyComponent( } } - const loggedComponent = - getComponentNameFromType(Component) || - // eslint-disable-next-line react-internal/safe-string-coercion - '' + Component; + const loggedComponent = getComponentNameFromType(Component) || Component; // This message intentionally doesn't mention ForwardRef or MemoComponent // because the fact that it's a separate type of work is an