Rendering React on the server

September 28, 2020

Intro

Today, we'll try out rendering react components from Node.js server. React is not bound only to browser for rendering, it can only be rendered through server. Since a server can't actually display rendered HTML, its role in such a situation is only to send a rendered markup to the browser as string.

Why

Why would anyone care about server side rendering your React code?

  • Initial render is faster. We can leave better first impression on user since our app has low First User Interaction Time. In Lighthouse report it is one of the metrics tracked in Performance section. Generated string of rendered markup is faster than rendering components in the browser.
  • All computation is left to the server. It means that user with low-end phone won't have to rely on its device as much.
  • Less network requests to fetch data since key ones happened on the server.

Code example

In code example we'll start from creating server, which will communicate with external api. After that fetched data will be passed to the component and then rendered to the HTML document. Let's start with React component:

/// App.js
import React from "react"

export const App = ({ users }) => {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  )
}

This code can be described as isomorphic javascript. It means that it can be run it and be shared both on the server and on the client side in the browser. All thanks to Node.js. You can read more about it here. Let's write our server with the help of Express framework.

import React from "react"
import { renderToString } from "react-dom/server"
import express from "express"
import axios from "axios"
import { App } from "./src/App"

const doc = content => `
       <!doctype html>
       <html>
         <head>
           <title>Rendering to strings</title>
         </head>
         <body>
<div id="app">${content}</div> </body>
</html> `

const app = express()

app.get("/", async (req, res) => {
  const { data } = await axios.get("https://jsonplaceholder.typicode.com/users")
  const rendered = renderToString(<App users={data} />)
  res.send(doc(rendered))
})

app.listen(8080, () => {
  console.log("Listening on 127.0.0.1:8080")
})

First we import all the packages and function that we'll need to render React component on the server. We create a function through which we will pass our React component as a string into HTML document structure. Then we create express application and we make it listen on port 8080. In next step we create route, which will respond on GET request with HTML structure that we want. To do that first we have to get our data from external API. I used here API called JSON placeholder. Then we render our React component as a string to the variable together with fetched data that we pass as its props. Last step is to send HTML structure as a response to the GET request.