React Router Introduction

Posted on March 07, 2019


React Router is a third party library created to solve the problem of routing in React app. It wraps around the browser history API and does the job of keeping your React application UI in sync with the browser's URL.

There are two packages of React Router: react-router-dom for React and react-router-native for React Native. Since you're learning about making web application, you only have to install react-router-dom:

npm install react-router-dom

There are 3 basic React Router components commonly used in minimal navigation, they are BrowserRouter, Route and Link. Let's explore about BrowserRouter and Route first:

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

class RouterNavigationSample extends React.Component {
  render() {
    return (
      <Router>
      <>
        <NavigationComponent />
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </>
      </Router>
    )
  }
}

The BrowserRouter, which is imported as Router, acts as the parent component that wraps all of your React component. It will intercept Browser request URL and match its path with the corresponding Route component. So if the browser URL is localhost:3000/about, the Router will take that information and than look for a Route component that has the path attribute of /about.

You will determine what will be rendered by adding the component attribute to Route.

In the sample above, an exact attribute is added to the default Route path (/), because without it, any route with / will also render the Home component, causing inconsistencies in the navigation.

The third component Link is used for navigation, replacing the regular <a> tag of HTML. This is because a regular HTML anchor tag will do a full refresh of the browser on click, which is not suited for React application. A React app only needs to update the URL, browser history and component rendered without any browser refresh:

import { Link } from "react-router-dom";

class NavigationComponent extends React.Component {
  render() {
    return (
      <>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About page</Link>
          </li>
        </ul>
        <hr />
      </>
    );
  }
}

You can try a working demo here.

Note how you can use the previous and next button of the browser's navigation bar, and the url is updated with subsequent navigation, without the browser loading. This is the power of React Router in action.

Making dynamic routing

You've seen how to create simple navigation using React Router, yet most web application require more advanced function than that. You probably need a dynamic routing, where you can put something like /user/:id, in which React needs to render something based on the value of :id.

Old links can also be dead and need to be redirected to new link.

Also, if the browser URL doesn't match any existing route, you need to display a 404 page.

That's why you need to learn about 2 more components, Switch and Redirect. Switch is a unique component that will render the first matching Route, then stop. To illustrate this example:

import { Route } from 'react-router'

<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>

In the above code, a browser URL of /about will match all three routes, causing it all to be rendered and stacked below each other. Now by using the Switch component, React Router will render the About component route and then stop.

import {Switch, Route} from 'react-router';

<Switch>
  <Route path='/about' component={About} />
  <Route path='/:user' component={User} />
  <Route component={NoMatch} />
</Switch>;

The order of the Route component inside Switch is important, so make sure you declare all static route first before declaring routes with url parameter and 404 route.

Now for Redirect, the component is pretty simple. You only need to add from attribute that states the old URL and to attribute specifying the new URL to link to.

import {Redirect} from 'react-router';

<Redirect from='/old-match' to='/will-match' />;

Nested route

In order to create nested route, you need to declare another Route inside the parent component. For example, let's say you have /users route that render to Users component.

Let's do a little exercise. First, create an array of objects that store user data, the following will do:

const users = [
  {
    id: '1',
    name: 'Nathan',
    role: 'Web Developer',
  },
  {
    id: '2',
    name: 'Johnson',
    role: 'React Developer',
  },
  {
    id: '3',
    name: 'Alex',
    role: 'Ruby Developer',
  },
];

Now create a simple routing in the application:

class RouterNavigationSample extends React.Component {
  render() {
    return (
      <Router>
        <>
          <NavigationComponent />
          <Route exact path='/' component={Home} />
          <Route path='/about' component={About} />
          <Route path='/users' component={Users} />
        </>
      </Router>
    );
  }
}

The NavigationComponent is where you write the Link component for navigating the application:

class NavigationComponent extends React.Component {
  render() {
    return (
      <>
        <ul>
          <li>
            <Link to='/'>Home</Link>
          </li>
          <li>
            <Link to='/about'>About page</Link>
          </li>
          <li>
            <Link to='/users'>Users page</Link>
          </li>
        </ul>
        <hr />
      </>
    );
  }
}

It's time to create components to render on specific routes. Home and About component will render a single div, while Users will have another Link and Route component.

Inside the Users component, you will render a list of users, with a nested route to individual user by its ID, like /users/:id:

const Home = () => {
  return <div>This is the home page</div>;
};

const About = () => {
  return <div>This is the about page</div>;
};

const Users = () => {
  return (
    <>
      <ul>
        {users.map(({name, id}) => (
          <li key={id}>
            <Link to={`/users/${id}`}>{name}</Link>
          </li>
        ))}
      </ul>
      <Route path='/users/:id' component={User} />
      <hr />
    </>
  );
};

There's nothing new with this code. So you can write the User component now:

const User = ({match}) => {
  const user = users.find((user) => user.id === match.params.id);

  return (
    <div>
      Hello! I'm {user.name} and I'm a {user.role}
    </div>
  );
};

Now here is something new I haven't told you about. Every time a component is rendered in a specific route, the component receive route props from React Router. There are 3 route props being passed down into component: match, location, history.

You can look at the props by opening the React Developer Tools and highlight the matching component route:

Route props

(If you're opening from Codesandbox, you can open the demo in a new separate window to enable React DevTool)

Notice how you add /:id URL parameter in the Users component nested route. This id is passed down to the User component through the match.params.id object property. If you passed the URL parameter as /:userId, it will be passed down as match.params.userId.

Now that you know about route props, let's refactor Users component a bit:

const Users = ({ match }) => {
  return (
    <>
      <ul>
        {users.map(({ name, id }) => (
          <li key={id}>
            <Link to={`${match.url}/${id}`}>{name}</Link>
          </li>
        ))}
      </ul>
      <Route path={`${match.url}/:id`} component={User} />
      <hr />
    </>
  );
}

As always, here is a working demo.

Passing props to Route component

You might think that passing props into Route component is the same as passing into regular component:

<Route path="/about" component={About} user='Jelly'/>

Unfortunately, React Router doesn't forward the props entered into Route component into the component props, so you have to use another method.

Fortunately, React Router provides a render attribute that accepts a function to be called when the URL locations matches. This props also receives the same route props as the component props:

<Route
  path="/about"
  render={props => <About {...props} admin="Bean" />}
/>

// the component
const About = props => {
  return <div>This is the about page {props.admin}</div>;
};

First, you take the given props from React Router and pass it into the component, so that the component can use match, location or history props if necessary. Then you add your own extra props into it. The example above use arbitrary admin props as example.

You can see the full code here.

Now you've learned about React Router, try to implement it for your React application!

Share this:
LinkedIn
Reddit
WhatsApp

Get Free Guides