Skip to main content

SSR React Server Components

Before reading this document, please read:

  1. Create React Server Component without SSR
  2. Add Streaming and Interactivity to RSC Page

These documents provide essential background on React Server Components and how they work without Server Side Rendering (SSR).

Static split-screen comparison showing why stream_react_component with renderToPipeableStream is required for RSC (supports Suspense and async), while react_component with renderToString breaks on async Server Components.

Update the React Server Component Page

Let's make React on Rails server-side render the React Server Component Page we created in the previous articles.

Update the react_server_component_without_ssr.html.erb view to pass prerender: true to the react_component helper.

<%= react_component("ReactServerComponentPage",
prerender: true,
trace: true,
id: "ReactServerComponentPage-react-component-0") %>

If this page contains a component that suspends while react_component is using React's synchronous renderToString path, the request fails with an error like this:

The server did not finish this Suspense boundary: The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server

This error occurs because the react_component helper uses React's renderToString function, which renders the React page synchronously in a single pass. The page from the previous step may still render if all children are synchronous, but this path isn't suitable for React Server Components once they contain asynchronous operations or async props that need progressive streaming.

Instead, we need to use the streaming capabilities provided by React on Rails Pro, as detailed in the Streaming SSR guide. These helpers internally use React's renderToPipeableStream API, which supports:

  1. Server-side rendering of async components
  2. Progressive streaming of HTML chunks to the client as components finish rendering
  3. Incremental hydration, where each component can be hydrated independently as it loads, rather than waiting for the entire application

To enable streaming SSR for React Server Components, we need to:

  1. Create a new view called react_server_component_ssr.html.erb with the following content:

    # app/views/pages/react_server_component_ssr.html.erb
    <%= stream_react_component("ReactServerComponentPage",
    id: "ReactServerComponentPage-react-component-0") %>

    <h1>React Server Component with SSR</h1>
  2. Ensure our controller includes ReactOnRailsPro::Stream and use the stream_view_containing_react_components helper to render the view:

    # app/controllers/pages_controller.rb
    class PagesController < ApplicationController
    include ReactOnRailsPro::Stream

    def react_server_component_ssr
    stream_view_containing_react_components(template: "pages/react_server_component_ssr")
    end
    end
  3. Add the route to config/routes.rb:

    # config/routes.rb
    get "/react_server_component_ssr", to: "pages#react_server_component_ssr"

Now, when you visit the page, you should see the entire React Server Component page rendered in the browser. And if you viewed the page source, you should see the HTML being streamed to the browser.

Next Steps

Now that you understand how to enable server-side rendering (SSR) for your React Server Components, you can proceed to the next article: Selective Hydration in Streamed Components to learn about React's selective hydration feature and how it improves page interactivity.