Community for developers to learn, share their programming knowledge. Register!
Routing with React Router

Server-side Rendering with React Router


You can get training on server-side rendering (SSR) with React Router through this article. SSR is an essential concept in modern web development, especially for developers looking to improve their application's performance and SEO. When combined with React Router, SSR becomes a powerful tool for building dynamic, performant, and SEO-friendly applications. In this article, we will explore SSR in detail, focusing on how it works with React Router, its benefits, implementation, and data-fetching techniques.

Understanding Server-side Rendering (SSR)

Server-side rendering (SSR) refers to the process of rendering web pages on the server instead of the client. Unlike client-side rendering (CSR), where the browser executes JavaScript to generate HTML, SSR sends fully-rendered HTML from the server to the browser. This approach allows web applications to load faster, especially for users with slow internet connections or devices with limited computing power.

In the context of React, SSR generates HTML on the server using React components and sends it to the client. React Router, a popular library for managing routing in React applications, can integrate seamlessly with SSR to enable dynamic, route-specific rendering on the server.

Historically, SSR gained prominence as developers sought ways to improve search engine optimization (SEO) and user experience. Search engine crawlers often struggle with JavaScript-heavy applications rendered entirely on the client, but SSR eliminates this issue by providing pre-rendered content. React Router plays a critical role in this process by handling route management during the server-side rendering pipeline.

Setting Up SSR with React Router

Setting up server-side rendering with React Router requires configuration of both the server and the React application. Here's a step-by-step guide to implementing SSR with React Router:

Install Required Dependencies: To set up SSR, you need essential libraries such as react, react-dom, react-router-dom, and react-router. Additionally, you'll need express for creating a server. Install these dependencies using npm or yarn.

npm install react react-dom react-router-dom express

Create a React Application with Routes: Define your routes using React Router. For example:

import React from 'react';
import { Routes, Route } from 'react-router-dom';

const Home = () => <h1>Home Page</h1>;
const About = () => <h1>About Page</h1>;

const App = () => (
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/about" element={<About />} />
  </Routes>
);

export default App;

Set Up a Server Using Express: Create an Express server that handles incoming requests and renders the application using React's renderToString method.

import express from 'express';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom/server';
import App from './App';

const app = express();

app.use(express.static('public')); // Serve static files

app.get('*', (req, res) => {
  const context = {};
  const appHtml = renderToString(
    <StaticRouter location={req.url} context={context}>
      <App />
    </StaticRouter>
  );

  const html = `
    <!DOCTYPE html>
    <html>
      <head><title>React SSR</title></head>
      <body>
        <div id="root">${appHtml}</div>
        <script src="/bundle.js"></script>
      </body>
    </html>
  `;
  res.send(html);
});

app.listen(3000, () => console.log('Server is running on http://localhost:3000'));

Bundle the React Application: Use a bundler like Webpack or Vite to generate the client-side JavaScript bundle. Make sure the server serves this bundle to hydrate the app on the client.

By following these steps, you can successfully implement SSR with React Router, enabling your app to serve pre-rendered HTML from the server.

Benefits of SSR for SEO and Performance

Integrating SSR with React Router provides significant advantages for SEO and performance:

  • Improved SEO: Search engine crawlers rely on HTML content to index pages. SSR ensures that all routes return fully-rendered HTML, making it easier for crawlers to understand your application's structure and content.
  • Faster Initial Page Load: Since the server sends pre-rendered HTML, users see the page content almost immediately, even before the JavaScript bundle loads. This is especially beneficial for users on slow networks.
  • Enhanced User Experience: SSR reduces the time to interactive (TTI) by prioritizing content delivery. Users perceive the application as faster and more responsive.
  • Social Media Sharing: When sharing links on social media, platforms like Facebook and Twitter scrape meta tags and page content. SSR ensures that these platforms retrieve accurate, pre-rendered data.

SSR is particularly valuable for content-heavy applications, e-commerce platforms, and sites with a focus on organic search traffic.

Data Fetching in SSR

Data fetching is a critical aspect of server-side rendering. React Router does not handle data fetching directly, but it provides the tools to integrate data-fetching mechanisms efficiently.

When implementing SSR, you need to ensure that data required for rendering a page is fetched on the server before sending the HTML to the client. Here’s how it typically works:

Determine Data Requirements for Each Route: Assign data-fetching logic to routes or components. For example, you can use a custom loadData function:

const routes = [
  {
    path: '/',
    element: <Home />,
    loadData: () => fetch('/api/home-data').then(res => res.json()),
  },
  {
    path: '/about',
    element: <About />,
    loadData: () => fetch('/api/about-data').then(res => res.json()),
  },
];

Fetch Data on the Server: Before rendering the app on the server, iterate through the matched routes and execute their data-fetching logic. Pass the fetched data as props to the React components.

const matchedRoute = routes.find(route => matchPath(route.path, req.url));
const data = await matchedRoute.loadData();

const appHtml = renderToString(
  <StaticRouter location={req.url} context={{}}>
    <App initialData={data} />
  </StaticRouter>
);

Hydrate Data on the Client: Serialize the server-fetched data and include it in the HTML response. On the client, use this data to hydrate the app and avoid duplicate API calls.

<script>
  window.__INITIAL_DATA__ = ${JSON.stringify(data)};
</script>

In your client code, access this data and use it to initialize your application.

By combining React Router with robust data-fetching strategies, you can build fully-functional SSR applications that deliver seamless user experiences.

Summary

Server-side rendering (SSR) with React Router is a powerful technique for building high-performance, SEO-friendly web applications. By rendering pages on the server and pre-fetching data for each route, SSR ensures fast initial page loads and improved search engine visibility. React Router's integration with SSR allows developers to implement dynamic routing while maintaining the benefits of server-side rendering.

In this article, we explored the fundamentals of SSR, the process of setting up SSR with React Router, and its advantages for SEO and performance. We also delved into data-fetching strategies, emphasizing the importance of pre-loading route-specific data on the server.

For intermediate and professional developers, mastering SSR with React Router opens up opportunities to create applications that stand out in terms of both functionality and user experience. Whether you're building a content-rich website or an e-commerce platform, SSR can help deliver a seamless, optimized experience for your users.

Last Update: 24 Jan, 2025

Topics:
React