{ React Router Continued. }

Objectives

By the end of this chapter, you should be able to:

  • Handle 404 errors with React Router and Switch
  • Use withRouter and Redirect to implement redirects in React

404s with React Router

Very commonly with routing, you will want a 404 handler for routes that do not exist. To do this with React Router v4, we use a component called Switch to wrap our routes. Switch will render the first child <Route> ( or <Redirect>, which we will see in a little bit) that matches the location.

You might be wondering, how is this different than just using a bunch of <Route> components? The answer is that <Switch> renders a single route inside of it. If multiple <Route> components match the path inside of a <Switch>, only the first one will render.

Consider this code:

import React from "react";
import { BrowserRouter, Route, Link, Switch } from "react-router-dom";

const NotFoundExample = () => (
  <BrowserRouter>
    <div>
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/will-not-match">More 404!</Link>
        </li>
        <li>
          <Link to="/dsajkdjsaldjskla">404 time!</Link>
        </li>
      </ul>
      <Switch>
        <Route path="/" exact component={Home} />
        <Route component={NotFound} />
      </Switch>
    </div>
  </BrowserRouter>
);

const Home = () => <div>Welcome home!</div>;

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

export default NotFoundExample;

You can read more about Switch here.

Redirecting Programatically

So far we have seen how to set up React Router with different types of routers, we've created routes, and we've passed props to our routes. This is a great start, but we're missing another essential concept with routing - redirecting!

When we redirect in a single page application, we are not doing the same thing as a normal HTTP redirect, which involves sending a location header and making a GET request to the value of that location header. We are simply making another AJAX request to load the correct information when we redirect.

With React Router v4 we are given access to a Redirect component which is useful for conditionally rendering or redirecting. We can also redirect with the help of a higher order component called withRouter, which will allow any component to access the router props.

Using withRouter to redirect

In the last chapter, we saw that when you write code like this:

<Route path="/" component={SomeComponent} />

then SomeComponent will have access to the three router props: match, location, and history. In particular, because it has access to the history prop, it's possible to issue a redirect, using the push method on history and supplying a new path. We'll see a code example of this momentarily.

This is great if you want to issue a redirect from SomeComponent. But what if you want to redirect from a component that isn't passed into Route, and therefore does not have access to the router's props? Fortunately, React Router solves this problem by providing us with a higher order component called withRouter. This function wraps a component and returns a new component which has access to the router props! Let's look at an example of an app that uses
history.push to issue a redirect on a button click.

import React, { Component } from "react";
import { Route, Link, withRouter } from "react-router-dom";

const Data = () => <h1>You made it!</h1>;

class Button extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.props.history.push("/data");
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click me!</button>
      </div>
    );
  }
}

const App = () => {
  const RouterButton = withRouter(Button);
  return (
    <div>
      <h2>Let's show the data component!</h2>
      <div>
        This button won't work!
        <Button />
      </div>
      <div>
        This button will!
        <RouterButton />
      </div>
      <Route path="/data" component={Data} />
    </div>
  );
};

export default App;

Using the Redirect Component

Along with withRouter, there is another way to redirect using the <Redirect/> component. Here's a quick example:

import React from "react";
import "./App.css";
import { Route, Link, Switch, Redirect } from "react-router-dom";
import ParamsExample from "./ParamsExample";

const Private = () => (
  <div>
    <h1>GO AWAY THIS IS PRIVATE</h1>
  </div>
);

const Public = () => (
  <div>
    <h1>hello! so nice to see you!</h1>
  </div>
);

const FeelingLucky = () => {
  const to = Math.random() < 0.5 ? "/public" : "/private";
  return <Redirect to={to} />;
};

const App = () => (
  <div>
    <ul>
      <li>
        <Link to="/public">Public Page</Link>
      </li>
      <li>
        <Link to="/private">Private Page</Link>
      </li>
      <li>
        <Link to="/lucky">I'm Feeling Lucky</Link>
      </li>
    </ul>
    <Route path="/public" component={Public} />
    <Route path="/private" component={Private} />
    <Route path="/lucky" component={FeelingLucky} />
  </div>
);

export default App;

In this example, the /lucky route redirects to either /public or /private, depending on the size of a randomly generated number.

You can read more about <Redirect/> here.

Additional Examples of Redirecting

Take a look at this example in the React docs and work your way through what is happening. Click around and see waht the code on the right is doing.

When you're ready, move on to React Router Exercise

Continue

Creative Commons License