Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Don't prerender siblings of suspended component (#26380)
Today if something suspends, React will continue rendering the siblings of that component. Our original rationale for prerendering the siblings of a suspended component was to initiate any lazy fetches that they might contain. This was when we were more bullish about lazy fetching being a good idea some of the time (when combined with prefetching), as opposed to our latest thinking, which is that it's almost always a bad idea. Another rationale for the original behavior was that the render was I/O bound, anyway, so we might as do some extra work in the meantime. But this was before we had the concept of instant loading states: when navigating to a new screen, it's better to show a loading state as soon as you can (often a skeleton UI), rather than delay the transition. (There are still cases where we block the render, when a suitable loading state is not available; it's just not _all_ cases where something suspends.) So the biggest issue with our existing implementation is that the prerendering of the siblings happens within the same render pass as the one that suspended — _before_ the loading state appears. What we should do instead is immediately unwind the stack as soon as something suspends, to unblock the loading state. If we want to preserve the ability to prerender the siblings, what we could do is schedule special render pass immediately after the fallback is displayed. This is likely what we'll do in the future. However, in the new implementation of `use`, there's another reason we don't prerender siblings: so we can preserve the state of the stack when something suspends, and resume where we left of when the promise resolves without replaying the parents. The only way to do this currently is to suspend the entire work loop. Fiber does not currently support rendering multiple siblings in "parallel". Once you move onto the next sibling, the stack of the previous sibling is discarded and cannot be restored. We do plan to implement this feature, but it will require a not-insignificant refactor. Given that lazy data fetching is already bad for performance, the best trade off for now seems to be to disable prerendering of siblings. This gives us the best performance characteristics when you're following best practices (i.e. hoist data fetches to Server Components or route loaders), at the expense of making an already bad pattern a bit worse. Later, when we implement resumable context stacks, we can reenable sibling prerendering. Though even then the use case will mostly be to prerender the CPU-bound work, not lazy fetches.
- Loading branch information