Turn Your Application Into a Single-Page App With React Router

Understand the Basics of SPA

LetĀ travel back to the very beginnings of the World Wide Web. šŸ¤–

At that time,Ā most websites consisted of a group of pages sent by the server, which rendered as users navigated through the site. For every interaction, like sending a form, the whole page had to be refreshed.

However, at the start of the new millennium, the concept of single-page applications (SPA) started to emerge. The main ideas behind this concept are:

  • Users only load a web page once (the famous Ā index.htmlĀ  ).

  • Rather than getting every page with an API call, you get them bit by bit,Ā making user interaction much more dynamic.

  • As users navigate between different pages, JavaScript (in our case, React) manages the rendering of new pages within the same domain without needing the page to refresh completely .Ā 

Classic website rendering at the top is less dynamic than the SPA below.
Classic website rendering at the top is less dynamic than the SPA below

Does that mean that SPA is better? Are all new sites coded to be SPA?

Well, no. Not all applications are SPA. There are certain drawbacks to be aware of when you code a website as a single-page application. In particular, your users will have to have JavaScript for your site to work, and search engine optimization (SEO) is harder for single-page applications.

The projects made with Create React App aren’t considered single-page applications as they lack aĀ routingĀ solution.

React Router

Unlike frameworks such as Angular, React does not directly provide a solution for managing your application’s routes. Not a problem, though – like with almost everything in React, the ecosystem quickly addressed this need, and now several routing solutions exist. We'll work with React Router (well-named, don't you think? šŸ™ƒ) in this course.

What exactly is a route?

AsĀ you can see in the React Router documentation, a route allows you to conditionally render components if the URL path matches the route path.

You pass the path that the route matches as a prop, which takes care of rendering the children that are passed to it.

This library, created by React Training, provides access to all of the tools needed to manage client-side, in-app navigation.Ā 

So let’s get familiar with React Router. šŸš€

Create Your First Routing FileĀ 

Start by installing the library with Ā yarn add react-router-domĀ  . If you want to learn more about its configuration,Ā read the React Router documentation.

You can now start using React Router! šŸŽ‰

So far,Ā Ā HomeĀ  is the only feature, so let’s create a new component for the survey.

To do this,Ā make aĀ  Ā Survey.jsxĀ Ā  file inĀ  Ā pagesĀ  . For now,Ā let's keep the component simple:

function Survey() {
    return (
        <div>
            <h1>Survey 🧮</h1>
        </div>
    )
}

Your mission is to enableĀ navigation between the homepage and the survey.Ā šŸ•µļøā€ā™€ļø

As you’ve probably already guessed, to do this, you’re going to use React Router and its Router and Route components.

Let’s start with the router. Place it at the root of the component tree to cover all of the routes that you define.

Now you have the Ā index.jsxĀ  file at the project route:Ā 

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router } from 'react-router-dom'

ReactDOM.render(
    <React.StrictMode>
        <Router>
            <Home />
        </Router>
    </React.StrictMode>,
document.getElementById('root')
)

And now put all of the routes that will be accessible into the router.

We need to render the right component for this URL
YouĀ need to render the right component for this URL

So let’s create a route for the homepage and survey.

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router } from 'react-router-dom'

ReactDOM.render(
   <React.StrictMode>
      <Router>
         <Route path="/">
            <Home />
         </Route>
         <Route path="/survey">
            <Survey />
         </Route>
      </Router>
   <React.StrictMode>
)

If you head toĀ http://localhost:3000/, you’ll see the homepage. It’s a different story for http://localhost:3000/survey, though… Uh oh! Both are rendering! It's OK. All you need to do is add the prop Ā exactĀ  in your route forĀ  Ā HomeĀ  :

<Route exact path="/">
   <Home />
</Route>

It works perfectly! šŸš€

The routes return the right components and the home page is displayed correctly
The routes return the right components

However, it’s not really practical to type all of your URLs into the address bar to load the page. šŸ™ˆ

Navigate With Links

So let’s createĀ a header with links to different pages in the app.

In theĀ  Ā /components folderĀ  , create a newĀ  Ā /HeaderĀ  folder with an Ā index.jsxĀ  file inside it, which gives youĀ Ā /components/Header/index.jsxĀ  :

import { Link } from 'react-router-dom'
function Header() {
   return (
      <nav>
         <Link to="/">Home</Link>
         <Link to="/survey">Survey</Link>
      </nav>
   )
}

export default Header

I usedĀ  Ā LinkĀ  , which comes from React Router and behaves like an Ā anchorĀ  tag. It is very important to use this to navigate so that your app is accessible (and not use redirections triggered by Ā onClickĀ  ).

Let’s now useĀ  Ā HeaderĀ  inĀ  Ā index.jsxĀ  at the project root:

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Home from './pages/Home'
import Survey from './pages/Survey'
import Header from './components/Header'

ReactDOM.render(
    <React.StrictMode>
        <Router>
            <Header />
            <Route exact path="/">
                <Home />
            </Route>
            <Route path="/survey">
                <Survey />
            </Route>
        </Router>
    </React.StrictMode>,
document.getElementById('root')
)

You now have the app base with navigation – congratulations! Great work! šŸš€

You’ve seen how to set up routing. Next, you’ll learn how to split your router when you have many routes to manage, for example, in a larger code project. Follow me in the screencast below!

Get Parameters in Your URLs

Navigation inĀ the application isĀ functioning well.

By clicking on the links, navigation is working within the app and the Home page and the Survey page are displayed accordingly.
By clicking on the links, navigation is working within the app.

But what ifĀ I want to pass parameters? For example, when I do the survey, to get each question number from the URL?

Good question! The router allows you to get parameters. To do this, you simply have to write your route like this in the Ā index.jsxĀ  file at the Ā /src routeĀ  :

<Route path="/survey/:questionNumber">
    <Survey />
</Route>

And then put a question number in Ā components/Header/index.jsxĀ :

function Header() {
return (
        <nav>
            <Link to="/">Home</Link>
            <Link to="/survey/42">Survey</Link>
        </nav>
    )
}

YouĀ get this parameter in Ā survey/index.jsxĀ  using the hookĀ  Ā useParamsĀ  Ā provided by React Router:

import { useParams } from 'react-router-dom'

function Survey() {
    const { questionNumber } = useParams()

   return (
       <div>
           <h1>Survey 🧮</h1>
           <h2>Question {questionNumber}</h2>
       </div>
    )
}

Congratulations! You’ve now got your question number as a parameter. ā˜€ļø

Create a 404 Page

Amazing – everything is working as hoped! But what happens if you type anything into the URL? For example, if you try to access http://localhost:3000/helloHowAreYou?

You can see the header, but nothing else. Wouldn’t it be better to signal to the user that nothing exists at this address? Have you ever heard of error pages? That’s what we’re going to do here: display a 404 page.

Start by creating a simple Ā ErrorĀ  component in Ā components/Error/index.jsxĀ  :

function Error() {
   return (
      <div>
         <h1>Oops šŸ™ˆ This page doesn’t exist</h1>
      </div>
   )
}

export default Error

Going back to the router, you’ll need to useĀ SwitchĀ from React Router: Ā SwitchĀ  allows you to render only the first route that matches the path, and you add a route to which you don’t pass a path prop.

So in the router, that gives you:

ReactDOM.render(
   <React.StrictMode>
      <Router>
         <Header />
         <Switch>
            <Route exact path="/">
               <Home />
            </Route>
            <Route path="/survey/:questionNumber">
                <Survey />
            </Route>
                <Route>
                    <Error />
                </Route>
            </Switch>
        </Router>
    </React.StrictMode>,
document.getElementById('root')
)

Let’s test it inĀ the browser:

The route displays an error message when the URL entered doesn’t exist in the router
The route displays an error when the URL entered doesn’t exist in the router

Yes! šŸ’Ŗ

Give It a Go!

Now thatĀ you have your application base, it’s time to see how youĀ do on your own.

You’ll find the base for the exercise on branch P1C3-begin. Your goals are to:

  • Create a newĀ  Ā ResultsĀ  page and add it to the router.

  • Create a newĀ  Ā FreelancersĀ  page, add it to the router, and create a link in the Ā HeaderĀ .

  • In Ā Survey.jsxĀ , code a link forĀ  Ā backĀ  andĀ one forĀ  Ā nextĀ  to allow users to move onto the next question or back to the previous one.Ā 

    • On question 1, the back link should not be active.Ā 

    • On question 10, the next link should not be displayed. Instead, a Results linkĀ shouldĀ redirect to the Results page.

You can find the solution on branch P1C3-solution.

Let’s Recap!

  • With single-page applications (SPAs), the user has the impression of navigating between different pages. However, only a single HTML page exists, onto which you graft the content with JavaScript.

  • React Router is one of the libraries you can use to turn a React app into a SPA.Ā 

  • The router, routes, and switch manage the rendering of different pages.

  • It is possible to pass parameters in a route and then get them with Ā useParams()Ā  .

  • By specifying a route with no path at the end of the switch, you capture all routes with a path that doesn't match any declared route, creating a 404 page.

The app now contains all of the pages for the next step! šŸŽ‰ In the following chapter, you'll see how to secure props with PropTypes. See you there!

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best