Upgrading to React 18 on the server #22
Replies: 8 comments 10 replies
-
Love the concrete clarity of this statements. |
Beta Was this translation helpful? Give feedback.
-
Do these changes also apply to the other existing render* APIs (renderToNodeStream, renderToStaticMarkup, etc)? I'm assuming yes but figured it'd be good to clarify 😄 |
Beta Was this translation helpful? Give feedback.
-
This page has been updated. We have added details to this page about the new APIs, and some existing ones. We also wrote up a deep dive on the architectural improvements to SSR in React 18. These improvements are substantial and are a culmination of several years of work: #37. |
Beta Was this translation helpful? Give feedback.
-
This is awesome 🔥, and the example is also very helpful 👌. I am very excited to try this out!
|
Beta Was this translation helpful? Give feedback.
-
Can |
Beta Was this translation helpful? Give feedback.
-
We can use the But what if we want to generate both types of HTML for the same tree? Not all User Agents will execute JavaScript, but may still need a final DOM. That means that during build time (or in the background, for e.g. Next's Incremental Static Regeneration) we may want want to render and cache both versions. But as of today, that would mean calling |
Beta Was this translation helpful? Give feedback.
-
There's |
Beta Was this translation helpful? Give feedback.
-
As mentioned in #104, the API |
Beta Was this translation helpful? Give feedback.
-
Overview
Upgrading to React 18 on the server has the following steps:
renderToString
torenderToPipeableStream
to unlock the new featuresReact 18 includes architectural improvements to React server-side rendering (SSR) performance described in New SSR Suspense Architecture. These improvements are substantial and are the culmination of several years of work.
API Changes
Previously, React did not support Suspense on the server at all. This is changing in React 18, but there are different levels of support depending on which API you use:
renderToString
: Keeps working (with limited Suspense support).renderToNodeStream
: Deprecated (with full Suspense support, but without streaming).renderToPipeableStream
: New and recommended (with full Suspense support and streaming).Existing API:
renderToString(React.Node): string
This API continues to work. It doesn’t support new features so we recommend switching to
renderToPipeableStream
. However, it’s not deprecated, so you can keep usingrenderToString
.In React 18, we’re adding very limited
<Suspense>
support torenderToString
. Previously, trying to use<Suspense>
with it threw an error. Starting in React 18, if you suspend duringrenderToString
, we will mark the nearest Suspense boundary as "client-rendered" and immediately emit the fallback HTML. Then, we will retry rendering its content on the client after the JS has loaded. Concretely, this means that if you wrap your app in a top-level<Suspense>
boundary and you suspend during rendering, your app effectively opts out of server rendering.This change shouldn't affect existing apps because suspending on the server previously did not work at all. However, if you tried to render
<Suspense>
on the client only by conditionally suspending, you may now get mismatches leading to content being removed from the DOM. Conditionally rendering different content on the server and the client’s first render is not (and has not been) supported in React in general.Deprecated API:
renderToNodeStream(React.Node): Readable
We will be deprecating
renderToNodeStream
completely in React 18—using it will warn. This was the first streaming API that we added, but it was very underpowered (it could not wait for data). It's also not commonly used. It will work in 18, including the new Suspense features described below, but it will buffer the entire content until the end of the stream. In other words, it will no longer do streaming. This makes its purpose confusing, which is why we’re deprecating it.We are replacing it with
renderToPipeableStream
.Recommended API:
renderToPipeableStream(React.Node, Options): Controls
This will be the recommended API going forward. It has all the new features:
<Suspense>
(which integrates with data fetching)lazy
without flashes of "disappearing" contentIn the latest Alpha versions, you can get it from:
Unlike
renderToString()
, it involves more wiring. We've prepared an example demo of how you could change your code from usingrenderToString()
torenderToPipeableStream()
. We will provide more detailed documentation later, but the demo should get you started.To learn more about what this API unlocks, read New SSR Suspense Architecture.
This API is not yet integrated with data fetching. The general Suspense mechanism should work, but we don't have a recommendation yet for how to transfer data from the server to the client to prepopulate the cache. We expect to provide more guidance on this in the future.
There are also some questions you'll want to experiment with. For example, how to deal with the
<title>
tags. Since this is a true streaming API, you might not have an "ideal" title by the time you start streaming. There are various solutions you could try, and we're curious to hear if you find something that works well for you as you test this API in your app and experiment with different approaches.Other APIs
There are a few other APIs related to generating static markup. Their behavior mirrors the main APIs:
renderToStaticMarkup
: Keeps working (with limited Suspense support).renderToStaticNodeStream
: Deprecated (with full Suspense support, but without streaming).The new recommended API for them that mirrors
renderToPipeableStream
has not been added yet.Beta Was this translation helpful? Give feedback.
All reactions