Routing in React With React Router
Tags: react, routing
Published: 2020-11-14 01:08:15

People who work with React should know that it is essentially a single page application (SPA). But but many React applications don’t present that way to a user. The user interacts with things on the page, and different components appear and disappear. A user interacts with the application as if it has many pages, so it makes sense for the URL to reflect this. This is where [React Router](https://github.com/ReactTraining/react-router) comes in.

First of all, since React is a SPA, all routing is Client-Side routing. This is in comparison to server side routing where each different URL makes a different GET request to the server. In Client-Side routing, the only thing the server does is render the HTML with the `'root' div` for React to render it’s virtual DOM. One benefit of this is the speed with which the different “pages” will appear for the user. The Client-Side route will just swap which component is rendered to the page instead of making a new server call, which can take some time. But on the flip side, the first page may take longer to load.

The best way to use Client-Side routing in React is to use React Router. This is a React library that uses specific URLs to tell React what components to render at each URL. To use it you have to install `react-router-dom` to your React app by running:

```
npm install react-router-dom
```

Now, to use `react-router-dom`, you have to decide what file or files you want to define the routes in your React app. The most common places for this is in index.js or the App component if you need to pass state down the component tree. App is usually where you keep the logic of how to organize the application, so it makes sense that it is the component that decides which components to show at each route. You also want to decide what routes you want to have.

For example, lets say you have a React application with a three main components: `Home`, `About`, and `FriendList`, which shows info about each friend in a list you have. At the top of the App.js file you would need to import all the components along with `react-router-dom`:

```
import Home from './Home'
import About from './About'
import FriendList from './FriendList'
import { BrowserRouter as Router, Route } from 'react-router-dom'
```

Importing `BrowserRouter` as `Router` is a common convention, so instead of using the term `BrowserRouter` in the component, you refer to it as `Router`. There are other things you can import from `react-router-dom`, but these are the main ones you’ll want to use to apply Client-Side routing.

Now that you’ve got everything imported, you’ll want to use the `Router` and `Route` components in the JSX returned from the App component (either the `render` method of a class component, or the `return` of a functional component):
```
return (
  <Router>
    <div>
      <Route exact path=”/” component={Home} />
      <Route exact path=”/about” component={About} />
      <Route exact path=”/friends” component={FriendList} />
    </div>
  </Router>
)
```
To unpack this example, first we’ll talk about the `Router` component. It is the base of our application’s routing, so it is where we declare how React Router will be used. It can also only have one child element, so that is why all the `Route` components are wrapped in a `<div>`.

Next we’ll talk about the `Route` component. In this example, they are taking two props, which basically equate to them saying “when the URL matches this `path`, render the given `component`.” The `exact` part just makes sure that the component is only rendered when the URL matches the path exactly. If we omitted the `exact` from all of the `Route`s, the `Home` component would render at any path with a `“/”` in it, in other words at every path.

`Route` can also be given the prop of `render` instead of `component`. `Render` takes a callback function as input so our example `Route`s would look like this:
```
<Route exact path=”/” render={() => <Home />} />
```
Using `render` is best when you have props from App that you want to send to it’s child components. It also has default props that you can pass through the callback function.

Another helpful thing `react-router-dom` has is the `NavLink` and `Link` components. When you import and use either of these components you can add links throughout your pages to other pages in the application. Both components function almost the same way, except you can add styling to `NavLink`s that show what page you are currently on. So for our example you could have a component called `Navbar` that you render on every page that looks like this:
```
import { NavLink } from 'react-router-dom'
const Navbar = () => {
  return (
    <div>
      <NavLink to=”/” exact>Home</NavLink>
      <NavLink to=”/about” exact>About</NavLink>
      <NavLink to=”/friends” exact>Friends</NavLink>
    </div>
  )
}
```
There is one last piece of routing functionality we are missing, and that is the ability to show the individual friends from our friend list at an individual page. The URL for this is commonly `'/friends/1'`, the `1` being the id of the friend being shown. Writing individual routes for each friend would be ridiculous, so the way we do this is with nested routes.

This requires some refactoring, so first off, we have to change App’s `FriendList` route to look like this:
```
<Route
  path='/friends'
  render={props => {
    <FriendList {...props} friends={this.state.friends}/>
  }}
/>
```
This `Route` uses `render` so that it can have access to a list of movies from state and the list of `props` with information about the route.

Then the `FriendList` component will render a list of `Link`s that each go to show page for a friend with the URL `'/friends/:id'` with the `id` being the id of the friend that’s being shown. It also defines a new `Route` that uses the `match` prop passed down:
```
const FriendList = ({ match, friends }) => {
  const renderFriends => {
    return friends.map(friend => {
      return <Link key={friend.id} to={`/friends/${friend.id}`}>
        {friend.name}
      </Link>
    })
  };
  return (
    <div>
      {renderFriends()}
      <Route
        path={`${match.url}/:friendId`}
        render={props => <Friend {...props} friends={friends} />}
      />
    </div>
  )
}
```
Now we need a way for the `Friend` component to know which friend from the list it should display. We do this through the `match` prop again:
```
const Friend = ({ match, friends }) => {
  return (
    <div>
      <h3>{ friends[match.params.friendId].name }</h3>
    </div>
  )
}
```
And with this we have fully functioning routes for visiting a a specific `friend` from the list.

Routing for an application may seem minor when thinking about the entirety of an application, but it can actually be very important. A user could have a favorite page in an app, and if they want to bookmark it, they need a URL to save. Routes can also be expressive to the user about what a certain page of an app is doing. Ultimately, routing is something all developers should take into careful consideration when designing their applications.