When using Suspense for data fetching, I've been using a pattern which I think it's pretty common, which is to wrap the suspended component into another that represents the data is being loaded (with either a message, a spinner, skeleton, etc). As an example:
function ProfileTimeline(props) {
// Try to read posts, although they might not have loaded yet
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
function SuspenseProfileTimeline(props) {
return (
<Suspense fallback={<div>Loading posts...</div>}>
<ProfileTimeline {...props} />
</Suspense>
);
}
export default SuspenseProfileTimeline;
However, repeating this pattern over an over, it feels too boilerplate-y, plus it feels as every component has this extra layer of indirection that creates 3 nested components (SuspenseProfileTimeline -> Suspense -> ProfileTimeline) when in fact it could be just one.
To solve this, I'd like to suggest adding sugar for Suspense within the same component. Maybe something like:
export function ProfileTimeline(props) {
// Try to read posts, although they might not have loaded yet
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
ProfileTimeline.suspenseFallback = (props) => <div>Loading posts...</div>;
export default ProfileTimeline;
Note that this would probably only be useful for data fetching (as for lazy loading you need to load the component to get the fallback), but I think it covers a use case that's common enough.
This a text book case for a HOC:
const SuspenseProfileTimeline = withSuspense(ProfileTimeline, (props) => <div>Loading posts...</div>)
That said, it shouldn't be commonly needed, since it almost entirely defeats the purpose of Suspense
I actually have it solved with HOCs to avoid code repetition on my projects, but I still think it would be nice to have it as part of React's API.
However, I don't fully understand
That said, it shouldn't be commonly needed, since it almost entirely defeats the purpose of Suspense
I thought the purpose of Suspense is to have a semantic way of representing what should be rendered in place of a component which is not yet ready to get rendered. So I don't fully understand how that pattern defeats Suspense's purpose.
Again, I am aware that this wouldn't be useful for React.lazy, but I think it does add value for data fetching.
I thought the purpose of Suspense is to have a semantic way of representing what should be rendered in place of a component which is not yet ready to get rendered.
The point of Suspense is to prevent the user from seeing too many loading states or fallbacks. This is achieved by the fact that a single <Suspense> boundary can have many suspending children. So, there are many components that need to fetch some data, but only a few places that can show fallbacks.
@vkurchatkin is right about not wanting to encourage a 1:1 map of loading-component-to-Suspense-component. That woudl probably lead to some undesirable loading sequences. That being said...
This looks like a substantial change being proposed. :smile: Changes like this should go through our RFC process:
https://github.com/reactjs/rfcs#react-rfcs
The RFC process is a great opportunity to get more eyeballs on your proposal before it becomes a part of a released version of React. Quite often, even proposals that seem "obvious" can be significantly improved once a wider group of interested people have a chance to weigh in.
The RFC process can also be helpful to encourage discussions about a proposed feature as it is being designed, and incorporate important constraints into the design while it's easier to change, before the design has been fully implemented.
Most helpful comment
@vkurchatkin is right about not wanting to encourage a 1:1 map of loading-component-to-Suspense-component. That woudl probably lead to some undesirable loading sequences. That being said...
This looks like a substantial change being proposed. :smile: Changes like this should go through our RFC process:
https://github.com/reactjs/rfcs#react-rfcs
The RFC process is a great opportunity to get more eyeballs on your proposal before it becomes a part of a released version of React. Quite often, even proposals that seem "obvious" can be significantly improved once a wider group of interested people have a chance to weigh in.
The RFC process can also be helpful to encourage discussions about a proposed feature as it is being designed, and incorporate important constraints into the design while it's easier to change, before the design has been fully implemented.