Server-side rendering — using a server to build static or prerendered HTML out of React component trees — is a feature of React that’s surprisingly easy to get started with. Although it’s frequently used for pre-rendering single page applications, let’s take a look at using this technique for non-SPA websites.

ReactDOMServer rendering methods

Server-side rendering with React is easy: React’s server-side rendering package is called ReactDOMServer, and it exposes two methods for rendering a React component. These methods are the server-side equivalents of ReactDOM.render(), however they return a string of the rendered HTML rather than mounting the component to a DOM node in a page.

ReactDOMServer.renderToString() is the method typically used for rendering a SPA server-side. This method returns HTML with hooks that allow client-side ReactDOM.render() to efficiently mount onto the available DOM without re-rendering everything.

ReactDOMServer.renderToStaticMarkup() is a less-used method that returns static HTML without any extra hooks for client-side React. This method is extremely interesting if we consider that not every website needs to be — or should be — a SPA.

Non-SPA use cases

Where would ReactDOMServer.renderToStaticMarkup() be useful?

Server-side templating

If you don’t need a React SPA client-side, rendering with React on the server is a forward-thinking approach. React is great not just for managing state within client-side applications, but also for architecting and developing reusable components across layers of abstraction.

Unlike the simplistic template partials or helpers offered by many server-side frameworks, React’s component and templating model encourages designing composable components, which I’ve found to facilitate reuse and ease maintenance over time. Let’s face it: find and replace for semi-complex HTML structures isn’t as nice as changing one encapsulated instance.

And as a bonus, front-end developers won’t need to learn the nuances of yet another language-specific templating language.

Static site generation

For convenience, I’ve been referring to ReactDOMServer’s rendering methods as server-side rendering, but do you need an application server that’s aware of React at all? For simple sites that might otherwise use Jekyll or another static site generator, there’s a case for React as an alternative.

As an example, this site is currently built with a simple set of scripts to orchestrate React in rendering each page at build time. This looks like the following:

import { renderToStaticMarkup } from 'react-dom/server';
import { Shell } from '../components/Shell';

const deleteRequireCache = path => delete require.cache[require.resolve(path)];
const prependDoctype = html => `<!DOCTYPE html>${html}`;

const renderJsxPage = async (filePath: string) => {
  const p = path.join(__dirname, '../', filePath);
  const { default: Page, metadata } = require(p);
  const content = renderToStaticMarkup(
    <Shell metadata={metadata}>
      <Page />
    </Shell>,
  );
  deleteRequireCache(p);
  return { content, metadata };
};
import React from 'react';
import { Metadata } from '../types';

export const metadata: Metadata = {
  title: 'Page title',
  description: 'Page description',
};

export default () => <div>Page content</div>;

What the build script does is render each page (written as a React component) to static HTML. Each page is wrapped with a common template for the site’s header and footer, and this template receives metadata exported from the page’s own module.

The result is both performant and a pleasure to work with.