Do you want to request a feature or report a bug?
A bug.
What is the current behavior?
Using <Suspense /> & lazy to lazy load components triggers the following warning:
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
It does however not affect functionality at all and the lazy loading & rendering of the component works fine.
**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.
https://codesandbox.io/s/mjzj27m0j8
What is the expected behavior?
Not trigger the warning as this should be a valid way of loading & rendering components according to the documentation.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
[email protected]
[email protected]
[email protected]
I believe it's due to this line <Suspense fallback={() => <div>loading...</div>}>
If you pull out that function and make it a component, e.g.
const Loading = () => <div>loading...</div>;
...
<Suspense fallback={<Loading />}>
then the error appears to go away. At least as a temporary solution to this problem.
Hey @rovansteen! This is expected behavior, and the fix that @frehner provided is the correct way to do it. Suspense expects that the fallback prop will be a React element not a React component. When you do:
<Suspense fallback={() => <div>loading...</div>}>
You're passing in a function component that renders a div with some text. What you need to do is pass _what that function would return_ directly
<Suspense fallback={<div>loading...</div>}>
Which is why @frehner's change works because <Loading /> is a React element for the Loading component.
You can think of Suspense as working something like:
function Suspense({children, fallback}) {
if (isSuspended) {
// It just returns whatever `fallback` is when rendering, it doesn't do
// <Fallback /> or anything like that.
return fallback;
} else {
return children;
}
}
So think of it just like you would children. What you're doing is equivalent to doing something like:
<Suspense>
{() => <div>Loaded!</div>}
</Suspense>
Hopefully that makes it clear why React would warn about that function not being a valid child.
Thanks for the explanation @aweary. I misread the documentation that correctly describes returning the component directly rather than a function. I was just confused because it did not crash and the loading of the component was too fast to see or notice the fallback. Cheers!
@rovansteen thanks for bringing it up! We should definitely make sure this is explicitly called out in the docs as I assume it will be a common mistake, and its easy to miss.
Are there any plans to enable the use of a function as value for children? I have currently the case that I don't want to introduce another component for loading the data, so I can pass it down to the component where I need the data and then this would be really useful:
<Modal open>
<Modal.Header>...</Modal.Header>
<Modal.Body>
<Suspense fallback={<p>Loading ...</p>}>
{() => {
const data = ModuleCache.read(id);
return (
<EditForm data={data} onChange={onChange} />
);
}}
</Suspense>
</Modal.Body>
</Modal>
Sure, I could also solve this problem with an IIFE, but to be honest: that's not the same as a native support by React itself.
@MeiKatz Me too ,could you resolve it now?
@MeiKatz Please file a new issue describing your use case and what exactly that helps you with. I don't think I understand it from a short description like this.
I'll lock this issue since it already attracts confusion (I don't know what @INTMIN's comment means). Please file new issues. Thanks.
Most helpful comment
Hey @rovansteen! This is expected behavior, and the fix that @frehner provided is the correct way to do it.
Suspenseexpects that thefallbackprop will be a React element not a React component. When you do:You're passing in a function component that renders a
divwith some text. What you need to do is pass _what that function would return_ directlyWhich is why @frehner's change works because
<Loading />is a React element for theLoadingcomponent.You can think of
Suspenseas working something like:So think of it just like you would children. What you're doing is equivalent to doing something like:
Hopefully that makes it clear why React would warn about that function not being a valid child.