React SSR (Streaming Server-Side Rendering)
Table of Contents
- Table of Contents
- History of React SSR
- Original Design Intent
- Improvements in React v16 SSR
- Improvements in React v18 SSR
- Implementation of Streaming SSR
- What is Hydration?
- Summary
History of React SSR
React’s Server-Side Rendering (SSR) has evolved through several versions. Here are the key milestones in its development:
- v0.4: Introduced the
React.renderComponentToStringAPI, marking the beginning of SSR support. - v0.12: Introduced
React.renderToStringto replace the original API. - 2015 v0.14: Split out the
react-dompackage and updated API calls toReactDOMServer.renderToStringandrenderToStaticMarkup. - 2016 v16: Introduced
ReactDOMServer.renderToNodeStreamandrenderToStaticNodeStream, adding support for streaming rendering. - 2020: Introduced RSC (React Server Components), further enhancing server-side rendering capabilities.
- 2022 v18: Introduced
renderToReadableStreamandrenderToPipeableStream, implementing a completely new server-side renderer.
Original Design Intent
By generating and completing the rendering of content on the server, React’s SSR provides a faster First Contentful Paint (FCP) compared to Client-Side Rendering (CSR). Here are the main advantages of SSR:
- Faster First Contentful Paint
- Because it’s streaming, content can be seen more quickly.
- Lower Server Resource Consumption
- Streaming rendering allows for content to be generated and sent simultaneously, reducing server load and resource consumption, and better handling concurrent requests.
Example Code
Server-Side Rendering
import { renderToString } from 'react-dom/server';
app.use('/', (request, response) => {
const html = renderToString(<App />);
response.send(html);
});
Client-Side Hydration
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document.getElementById('root'), <App />);
Improvements in React v16 SSR
Compared to v15, React v16’s SSR was optimized in the following areas:
- Smaller Generated HTML Size
- Removed the
data-reactIdattribute and comments, reducing the size of the HTML file.
- Removed the
- More Forgiving Hydration
- Looser attribute validation.
- Only replaces mismatched HTML subtrees instead of re-rendering the entire component tree.
- Faster Speed
- Removed the dependency on
process.env.NODE_ENV. - No Virtual DOM logic is involved in server-side rendering, improving rendering efficiency.
- Removed the dependency on
Improvements in React v18 SSR
React v18 introduced several improvements that further optimized SSR performance and experience:
- Error Handling and Hydration Fallback
- When a server-side error or hydration mismatch occurs, it no longer automatically falls back to Client-Side Rendering (CSR). With
Suspense, React can identify boundaries and perform partial fallbacks.
<Suspense fallback={<Loading />}> <Component /> </Suspense> - When a server-side error or hydration mismatch occurs, it no longer automatically falls back to Client-Side Rendering (CSR). With
- Selective Hydration
- Hydration is now handled selectively, allowing parts of the page that render first to become interactive sooner. This improves the initial user experience, especially in applications with slow API responses.
Implementation of Streaming SSR
Streaming SSR is a form of server-side rendering characterized by the real-time generation of HTML chunks that are sent to the client.
Example Code
import { renderToPipeableStream } from 'react-dom/server';
const { pipe } = renderToPipeableStream(<App />, {
bootstrapScripts: ['./main.js'],
onShellReady() {
response.setHeader('content-type', 'text/html');
pipe(response);
},
});
Solving Traditional SSR Problems
The steps for traditional SSR are as follows:
- Fetch Data: All data must be ready before the component can be rendered to HTML.
- Load JS: All component code on the client must be loaded before hydration can begin.
- Hydration: You must wait for all components to be hydrated before you can interact with them.
Solution
By using a server renderer that streams HTML out of order, combined with the capabilities of Suspense, you can flush the HTML generated earlier.
- Example Code
<Layout>
<NavBar />
<SideBar />
<RightPane>
<Post />
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
</RightPane>
</Layout>
import { use } from 'react';
function Comments() {
const comments = use(fetch('./api/comments'));
return (
<>
{comments.map((comment, i) => {
return <p key={i}>{comment}</p>;
})}
</>
);
}
In React v18, hydration can begin before the script for the Comments component has loaded. If the data is ready but the JavaScript code has not yet loaded, React will perform an initial hydration; once the script is loaded, it will hydrate again.
Lazy Loading Components
import { lazy } from 'react';
const Comments = lazy(() => import('./comments.js'));
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
What is Hydration?
Hydration is the process where React takes over the HTML nodes generated by the server (usually for an isomorphic React component) and primarily attaches event listeners to make the component interactive.
- Process:
- React converts the static HTML generated by the server into dynamic, interactive components.
- It attaches event listeners and other interactive logic on the client side.
- Importance:
- Hydration is a crucial step in SSR, ensuring that the content generated on the server can function correctly on the client.
Summary
React’s server-side rendering has evolved from simple string rendering to streaming rendering and selective hydration, significantly improving application performance and user experience. With the introduction of new features like Suspense and React Server Components, React v18 has further enhanced the flexibility and efficiency of SSR. In the future, as technology continues to advance, React’s SSR capabilities will continue to provide developers with more powerful tools for building high-performance web applications.
References
- New Suspense SSR Architecture in React 18 — Official React Working Group discussion on streaming SSR
- Rendering on the Web — web.dev — Google’s comprehensive guide to web rendering strategies
- React 18 Streaming SSR — YouTube (Jack Herrington) — Video tutorial on React 18 streaming SSR implementation