✨ Creating A React App

Photo by Rolands Zilvinskis on Unsplash

This is part 2 of my series on server-side rendering (SSR):

  1. 🤷🏻‍♂️ What is server-side rendering (SSR)?
  2. [You are here] ✨ Creating A React App
  3. 🎨 Architecting a privacy-aware render server
  4. 🏗 Creating An Express Server
  5. 🖥 Our first server-side render
  6. 🖍 Combining React Client and Render Server for SSR
  7. ⚡️ Static Router, Static Assets, Serving A Server-side Rendered Site
  8. 💧 Hydration and Server-side Rendering
  9. 🦟 Debugging and fixing hydration issues
  10. 🛑 React Hydration Error Indicator
  11. 🧑🏾‍🎨 Render Gateway: A Multi-use Render Server

Last week, I gave my own brief history of web sites and how their frontend implementation has drifted from entirely server-based, to entirely client-based, and is now settling (perhaps) with hybrid that we call server-side rendering (SSR). The goal of this journey is to poke around the gnarly bones of SSR and learn what we learn. We may make mistakes, break idioms, and portray ourselves as fools, but we will definitely learn. For that reason, we are not going to bother with things like Next.js, which have already fleshed over and hidden away the gnarly bones for us1.

Now, before we dip even further in the specific world of SSR, we are going to need an app. To be specific, we are going to need a React app.

Hello, React World!

Before creating a React app, we need a package manager; either npm or yarn will suffice. Though we could put together our own app from scratch, there is no need to as the handy create-react-app package exists. There are numerous ways to use this, but the easiest is to use yarn create or npx, which will do the work of obtaining the package and executing it all in one go.

For yarn, drop create from the front of create-react-app:

yarn create react-app <app-name-here>

For npx:

npx create-react-app <app-name-here>

I want to also put this in a git repository so I can track my changes. I would normally make a directory, run git init and then get started. In this case, we do not need to as create-react-app takes care of that for us.

So, let's begin. Open a terminal and invoke create-react-app.

yarn create react-app hello-react-world

After executing this, you will have a working React app that uses react-scripts to manage the basics. This is perfect for our initial journey. If we navigate to that directory and run the project, we can see our app in action.

cd hello-react-world
yarn start
Screenshot of the website created by the create-react-app tool. It shows the React logo in blue, over a dark grey background, with the text "Edit src/App.js and save to reload." and a link labelled, "Learn React"

Fantastic. We have an app. Before we do any more, let's get some remote source control underway. I am paranoid of my machine dying and losing all my work, so having an off machine place to store things is really useful. First, add a new repository on your source control site of choice (I prefer GitHub). Second, connect the local repository to the remote one:

git remote add origin <repo-url>
git fetch
git branch --set-upstream-to origin/master master

Since we want our local code to be the first commit and we're pushing to a brand new repository, we can force push what we have.

git push -f

Routing

Okay, we have an app and it is in source control. This is usually a good spot to spend some time setting up code quality tools like eslint and prettier. I am going to be naughty and skip right over that right now and save it for a different post, perhaps. Instead, let us add some routing to our fledgling application.

There are a few options for implementing routing in a React application (some frameworks, like Next.js, even provide it out of the box). We are going to use React Router. There are two variants of React Router; one for React on websites, and one for React Native on mobile. We want the website variant, which is provided by the react-router-dom package.

yarn add react-router-dom

Now we will edit our app to have a couple of routes. The main app is defined in the src/App.js file. It should look something like this. I have highlighted the lines we're going to replace; we are also going to add some too.

import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

There are two things we want to add.

  1. The routes to render our pages.
  2. The links to navigate to our routes.

First we import four things from react-router-dom:

  1. BrowserRouter
    This is the root of our React Router-based navigation. Basically, the router is responsible for the routing (I'm sure you guessed that).
  2. Link
    This replaces the anchor tag (<a>) for our navigation.
  3. Route
    This is used to render a matched route.
  4. Switch
    This allows us to specify a table of possible routes that can be used to work out what should handle the URL currently being viewed.

With these things, we can then add some routes. I am adding Home, About, and Contact. Here is my app code after the edit. I have highlighted the new lines.

import React from 'react';
import {BrowserRouter, Link, Route, Switch} from "react-router-dom";
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <div className="App-links">
            <Link className="App-link" to="/">Home</Link>
            <Link className="App-link" to="/about">About</Link>
            <Link className="App-link" to="/contact">Contact</Link>
          </div>
        </header>
        <section className="App-content">
          <Switch>
            <Route path="/about">
              This is the about page!
            </Route>
            <Route path="/contact">
              This is the contact page!
            </Route>
            <Route path="/">
              This is the home page!
            </Route>
          </Switch>
        </section>
      </div>
    </BrowserRouter>
  );
}

export default App;
Screenshot of the updated app using React router. The top shows the React logo with three links below it for "Home", "About" and "Contact" all on a dark grey background. Below that is a white region with the text "This is the home page!"

I also edited the CSS a little, but only to make things easier to see. The important bits are the router, wrapping our app, the Link components to perform navigation, and the Route components that render each route. With this, we now have a single page React app that has three pages for home, about, and contact.

This is going to be the application we will eventually render on the server. The important take away at this point is that we are not going to change the functionality of this app in order to achieve our aim. There are some changes we must make to support SSR, but we will not have two versions of the code. The code that runs in the browser will run on the server.

Next time, we are going to setup a server that will perform our SSR and consider what changes we need to make to our application infrastructure in order to support it. We might even get our first server-side rendered page. Until then, thanks for joining me on this continued exploration of server-side rendering using React.

  1. of course, if starting a new project knowing you need SSR, you should explore solutions like Next.js []