React js 18 RFC , issues and what is the feedback from the community ?
One issue that I saw with Next.js is that some folks are already using Suspense on the client, and such APIs might not work well with server rendering without additional changes.
Would it make sense to officially recommend something like having existing client-only suspense APIs start throwing an error when rendered on the server so that they fallback to client-rendering, until the API can be updated to properly support server-side Suspense?
One issue that I saw with Next.js is that some folks are already using Suspense on the client, and such APIs might not work well with server rendering without additional changes.
Is it the case where people do conditional rendering like {typeof window !== 'undefined' && <Suspense>...</Suspense>}
, or is this some other case? Currently, it throws on the server if rendered unconditionally. Rendering different content on the client and server based on a condition was never officially supported, so I'm not sure which scenario this refers to.
If it's the scenario I'm thinking of, the fix is usually to do rendering in two passes:
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
<div>
{mounted && <Suspense>...</Suspense>}
</div>
It's not great but would have the same behavior.
Would it make sense to officially recommend something like having existing client-only suspense APIs start throwing an error when rendered on the server so that they fallback to client-rendering, until the API can be updated to properly support server-side Suspense?
I'm not sure I understand what you're proposing. Is it to make renderToString
throw on Suspense nodes? Or something else? Thanks!
The case is not something that happens by just upgrading to newer React. It's when you first upgrade to newer React and then later start using existing Suspense-y APIs on the server and <Suspense>
"just works". Except it doesn't just work because the result isn't serialized in the stream so it might change and cause hydration errors.
So there's no conditional Suspense.
IMO, it's correct that an API that tries to be suspensey but doesn't have a way to transfer data to the client should throw an error if used on the server so that it deopts to client rendering and you get the correct client side warning.
Typically such an API has some way to provide initial data from getServerSideProps/getInitialProps. So it can throw only if that wasn't provided
I thought this was about using <Suspense>
for code splitting, but I see now the question was about using libraries that try to use Suspense for data fetching (which is not fully supported yet), and the fact that these libraries used to throw on the server, but now they may just subtly be broken. I agree it makes sense for them to throw explicitly until there is a way to transfer the data to the client.
The reason we didn't go with this approach in React 16.6 was for backwards compatibility reasons. At the time, most React code used classes, and many classes contained the `componentWillMount` method. This is why we renamed it to `UNSAFE_componentWillMount` in 2018 and [described](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html) strategies ot migrate away from it. The problem with `UNSAFE_componentWillMount` is that it fires during rendering (so, before we know whether child components suspended or not). If we throw away an incomplete tree after `UNSAFE_componentWillMount` has already fired, it will not receive a matching `componentDidMount` or `componentWillUnmount` call. (During a retry, there will be another `UNSAFE_componentWillMount` call because we need to render the same tree again.) So code that relies on `UNSAFE_componentWillMount` and `componentWillUnmount` being called the same number of times might cause mistakes or memory leaks.
We don't think this concern is relevant anymore for several reasons. `UNSAFE_componentWillMount` was marked as "unsafe" in 2018, and most popular open source libraries have long migrated away from it. This issue also only affects components "between" the `<Suspense>` node and the component that actually suspends. So it is very local in scope, and is easy to fix. Finally, Hooks have become a popular alternative to classes, and don't have the same issue. On the other hand, the current behavior [has been causing issues](https://github.com/facebook/react/issues/14536) for using popular component libraries with Suspense. This is why we think now is a good idea to make that change.