This content originally appeared on Telerik Blogs and was authored by Ifeoma Imoh
This post describes how the new Suspense SSR architecture introduced in React 18 solves the problems we currently face with server-side rendering in React.
The <Suspense>
component in React can be used to delay component rendering until the data for that component is ready. While waiting, you can display a placeholder or a fallback UI (spinner) and once the data is ready, React will render the component. This is possible because concurrent rendering (Asynchronous React) introduces an interruptible rendering process in React. Previously, because React’s rendering process (Synchronous React) couldn’t be interrupted, we had to use conditional statements to ensure that React doesn’t render a component before the data for that component is fetched.
When the first version of the <Suspense>
component was introduced in 2018, it could only be used to specify loading states and dynamically load code incrementally on the client using an API called React.lazy
—it couldn’t be used on the server at all.
React 18 includes some improvements to server-side rendering performance in React, which enables <Suspense>
on the server. This means that you can now use <Suspense>
and React.lazy
on the server. And guess what? That’s not all! <Suspense>
in React 18 also enables two major server-side rendering features unlocked by a new API called renderToPipeableStream:
- Streaming HTML on the server
- Selective Hydration on the client
Before we see how these features work and improve server-side rendering in React, we need to understand what server-side rendering (SSR) is and its problems.
React gets easier when you have an expert by your side. KendoReact is a professional UI component library on a mission to help you design & build business apps with React much faster. Check it out!
What Is Server-Side Rendering?
Server-side rendering (SSR) in React is the process of rendering React components to HTML on the server. The HTML is generated on the server and then sent to the client (browser). So unlike client-rendered apps where users see a blank page while waiting for the JavaScript to load in the background, SSR creates a better user experience by allowing your users to see the HTML version of your app.
Your users won’t be able to interact with the HTML until the JavaScript bundle loads. After the HTML is rendered in the browser, the React and JavaScript code for the entire app starts loading. When that is done, the JavaScript logic is then connected to the server-generated HTML, after which your user can fully interact with your app.
SSR in React in Four Steps
- Fetch data for the ENTIRE application on the server.
- Render the ENTIRE application to HTML on the server and then send it to the client.
- Load the JavaScript code for the ENTIRE application on the client.
- Connect the JavaScript code to the HTML for the ENTIRE application on the client—a process known as Hydration.
ENTIRE is written in capital letters in the steps above to emphasize that each step in the process must be completed for the whole application before the next step can begin.
I’m pretty sure the problem with SSR, in this case, is quite obvious now. For example, because we have to fetch the data for the whole application on the server and before sending it to the client, you can’t send the HTML for the fast parts of your application to the client when they are ready until the HTML for the slow parts is also ready. This is also the case for every step of SSR in React. The fact that each stage of the process must be completed for the whole app at once before the next stage can begin implies that the slow parts of your application will delay the fast parts.
As we know, with server-side rendering, your user has something to see (server-generated HTML) while waiting for the JavaScript to load, which is amazing, but the user experience can still be optimized. What if I told you that you could split your app into smaller chunks that would go through these processes separately? This way, the slow part of your app won’t affect the fast parts. That’s exactly what <Suspense>
does with the two new server-side rendering features introduced in React 18.
Streaming HTML on the Server
In React 18, you can wrap the parts of your app that may take some time to load with the <Suspense>
component. This way, you can start streaming down the server-rendered HTML for the components that are ready to your client without waiting for the components that may take some time.
<Layout>
<Article />
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
</Layout>
In the snippet above, wrapping the <Comments />
component in <Suspense>
tells React not to wait for that component to start streaming the HTML for the rest of the page to the client. While streaming, because we provided the <Spinner />
component as a fallback, the HTML for the <Spinner />
will be sent with the HTML for the rest of the page. Your users will see the spinner while waiting for the comments to load.
Once the data for <Comments />
becomes available, its HTML will be generated and sent into the same stream with a <script>
tag that will insert it in the right place. This eliminates the problem introduced by the first and second steps of SSR in React since we no longer need to fetch data for the entire application before sending the HTML down to the client.
Now we know that the JavaScript code for the entire application needs to be loaded for the next step—hydration—to begin. If the JavaScript code size for the <Comments />
is large, hydration will be delayed. This brings us to the second server-side rendering feature in React 18—selective hydration.
Selective Hydration on the Client
As seen above, wrapping the <Comments />
component in <Suspense>
tells React to go ahead and stream the HTML for the rest of the page from the server. Well, that’s not all. It also automatically tells React not to block hydration if the code for <Comments />
isn’t loaded yet.
This means that React will go ahead and start hydrating different parts of the application as they are loaded, and when the HTML for the <Comments />
section is ready, it’ll get hydrated. This solves the problem we have with the third and fourth steps of SSR in React because we no longer need to wait for the JavaScript for the entire app to load before hydration can begin.
One more interesting improvement happens behind the scenes when you wrap a component in <Suspense>
. React can now prioritize components users interact with during hydration and selectively hydrate them.
<Layout>
<Article />
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
<Suspense fallback={<Spinner />}>
<RelatedPosts />
</Suspense>
</Layout>
I added a section for <RelatedPosts />
in the snippet above and wrapped it in a suspense boundary so they can both be streamed from the server. Let’s say the HTML for the <Comments />
and <RelatedPosts />
have been streamed, and their code has been loaded. React will start with hydrating <Comments />
because it is higher in the component tree.
While <Comments />
is hydrating, if a user clicks on <RelatedPosts />
, React will record the click event and pause the hydration for the <Comments />
and start the hydration for the <RelatedPosts />
so that it can become interactive. Because that’s what the user is interested in, it is considered urgent. After hydrating <RelatedPosts />
, React will go back and continue hydrating the <Comments />
.
This is amazing because React prioritizes parts of your application that the user is interested in, and the hydration process does not need to be completed for the entire application before your users can start interacting with it.
Conclusion
React is synchronous, but with the <Suspense>
SSR architecture in React 18, you can serve parts of your application to your users asynchronously by specifying what should happen when another component isn’t ready or when the JavaScript for a component isn’t loaded. These improvements unlocked by the <Suspense>
component solve many SSR issues in React. See the Working Group Discussions for more on the Suspense SSR architecture in React 18.
Next, you may want to read this post about Concurrent Rendering in React 18.
This content originally appeared on Telerik Blogs and was authored by Ifeoma Imoh
Ifeoma Imoh | Sciencx (2022-03-09T10:23:01+00:00) Suspense on the Server in React 18. Retrieved from https://www.scien.cx/2022/03/09/suspense-on-the-server-in-react-18/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.