Handling 404 pages (catch all routes) with React Router v4

4 min read.
This post is part of our React Router v4 course. Ok. Continue on with the free post.

Often time when building an app with React Router, you want to have a ‘catch all’ route which will render if none of the other routes match. In this post, we’ll learn how to do just that by breaking down the ‘No Match (404)’ example from the React Router docs.

Video

Post

A common use case for when you’re building an app with React Router is to have a “catch all” route that will be rendered if none of your other routes match. A good example of this is if you wanted your client side router to render a 404 page. In order to see how this works, let’s first render a navbar with the following paths - /, /will-match, /will-not-match, and /also/will/not/match.

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

class App extends React.Component {
  render() {
    <Router>
      <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/will-match">Will Match</Link></li>
          <li><Link to="/will-not-match">Will Not Match</Link></li>
          <li><Link to="/also/will/not/match">Also Will Not Match</Link></li>
        </ul>
      </div>
    </Router>
  }
}

export default App

Now that we have the navbar set up, let’s create three different components to render - Home, which will match on /, WillMatch which will match on /will-match, and NoMatch, which will be the catch all component which will render if none of the other route’s match.

const Home = () => (
  <h1>
    Home
  </h1>
)

const WillMatch = () => <h3>Matched!</h3>

const NoMatch = ({ location }) => (
  <div>
    <h3>No match for <code>{location.pathname}</code></h3>
  </div>
)

Now that we have the components which are going to be rendered, we need to actually render some Routes. Home and WillMatch are straight forward. They just get rendered as they normall would.

render() {
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/will-match">Will Match</Link></li>
        <li><Link to="/will-not-match">Will Not Match</Link></li>
        <li><Link to="/also/will/not/match">Also Will Not Match</Link></li>
      </ul>

      <Route path="/" exact component={Home}/>
      <Route path="/will-match" component={WillMatch}/>
    </div>
  </Router>
}

But how do we render NoMatch? Here’s one tip that will get us closer. If you render a Route but don’t specify a path prop, that route will always be rendered. Knowing that, we could throw a new Route with no path that rendered NoMatch at the end of our routes?

<Route path="/" exact component={Home}/>
<Route path="/will-match" component={WillMatch}/>
<Route component={NoMatch} />

Ok, cool. But it still doesn’t work. Now the app renders the Home and WillMatch components properly but it also always renders the NoMatch component no matter what path we’re on, because the Route has no path, and if it has no path, it will always be rendered… 👨‍💻

What we need is a way to tell React Router that we only want to render the first Route that matches, even if there’s more than one match. This way, if the / or /will-match paths match, the router will render the associated component, and if not, it will render the NoMatch component. The good news is React Router comes with a component that does exactly this and it’s called Switch. All we need to do is wrap our Routes inside of a Switch then just as we wanted, only the first match will ever be rendered.

render() {
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/will-match">Will Match</Link></li>
        <li><Link to="/will-not-match">Will Not Match</Link></li>
        <li><Link to="/also/will/not/match">Also Will Not Match</Link></li>
      </ul>

      <Switch>
        <Route path="/" exact component={Home}/>
        <Route path="/will-match" component={WillMatch}/>
        <Route component={NoMatch} />
      </Switch>
    </div>
  </Router>
}

🕺 Now if the user isn’t at / or /will-match, the NoMatch component will be rendered.

Liked this post? Share it 🕺

Newsletter

Listen, I get it, newsletters are the worst.

But, as Louis from Colorado says, "This newsletter sucks less than the others".

We only send spam. That's a joke.