React Router v4: Philosophy and Introduction
Tags: react, javascript, reactrouter
Published: 2018-01-14 18:45:53

---
title: 'React Router v4: Philosophy and Introduction'
description: "React Router v4 introduces a new dynamic, component based approach to routing. In this post, we'll talk about the philosophies behind React Router and give an introduction to the syntax by breaking down the 'Basic' example on the React Router docs."
articleImage: "https://tylermcginnis.com/static/4d5aac8b48dc765f1d9a4a76ccde797d-79f0b.png"
tags: "react, javascript, react-router"
cover_image: "https://tylermcginnis.com/static/4d5aac8b48dc765f1d9a4a76ccde797d-79f0b.png"
canonical_url: "https://tylermcginnis.com/react-router-philosophy-introduction/"
published: "true"
---

React Router v4 introduces a new dynamic, component based approach to routing. In this post, we'll talk about the philosophies behind React Router and give an introduction to the syntax by breaking down the "Basic" example on the React Router docs.

### Video

{% youtube 3B588JwyT18 %}

### Post

If you've been in React land for the last few years, you know that React Router has gone through a few different iterations. Say what you will, but it's clear that the React Router we have today (v4) is a huge improvement on previous versions. The reason for these changes are pretty standard - the authors today are more experienced React developers than they were when React Router was first built. You see, back in 2014, *everyone* was new to React. React itself was still under a year old and no one really knew to what extent this whole component thing would play out. With that in mind, it's natural that the first commits of React Router looked something like this

<img src='https://tylermcginnis.com/static/febc9b6d8bfdeeb1276fd7db6c2bf271-605ac.png' alt="React Router's first commits" />

At the time, both Michael and Ryan (the creators of React Router) were coming from Ember backgrounds. So naturally, the first version of React Router was similar in nature to that of Ember's router. That is, with both routers you'd establish your routes statically as part of the app's initialization process. In fact, mostly all of the router's you're probably familiar with are used this way - Express, Angular, Ember. Even React Router pre version 4 used static routes as well. Here's some code from React Router before version 4. Typically you'd have a `routes.js` file where you'd establish your static routes.

```js
// routes.js

const routes = (
  <Router>
    <Route path='/' component={Main}>
      <IndexRoute component={Home} />
      <Route path='playerOne' component={Prompt} />
      <Route path='playerTwo/:playerOne' component={Prompt} />
      <Route path='battle' component={ConfirmBattle} />
      <Route path='results' component={Results} />
      <Route onEnter={checkAuth} path='dashboard' component={Dashboard} />
    </Route>
  </Router>
)

export default routes
```

Then, when you'd initialize your app, you'd import your routes and render them.

```js
// index.js

import React from 'react'
import ReactDOM from 'react-dom'
import routes from './config/routes'

ReactDOM.render(routes, document.getElementById('app'))
```

This brings up the question, "is static routing bad?". The answer to that is obviously, no. One could argue it's not really the "React way" of doing things though. Since its creation, not only have the creators of React Router become more experienced in the intricacies of building a router, but they've naturally also gained more experience with React itself, so much so their full time jobs are to teach it. What they found during their workshops was that the principles they taught about React, like component composition, didn't align with the actual API of React Router. Not only that, but in some places they were actually competing with the React API. Looking back at the previous example, we pass an `onEnter` prop to the `<Route>` component.

```js
<Route onEnter={checkAuth} path='dashboard' component={Dashboard} />
```

The idea here is that before the user sees the `Dashboard` component, the `checkAuth` function verifies the user is authenticated. Well, doesn't that sound similar to what should happen inside of `Dashboard`'s `componentDidMount` lifecycle hook? It is.

With previous versions of React Router, it was more of a router for React than an actual React router. React Router v4 was built fix these inconsistencies and work with React, rather than against it. If you're already familiar with the benefits of React and the benefits of component composition, React Router v4 is going to make you feel at home - you just need to forget everything you know about traditional static routers.

Now the question is why is it that React Router v4 aligns nicely with React when previous versions fought against it? The answer is because it ditched static routing in favor of dynamic routing and the entire API is just components. What that means is that you declare your routes as part of your application just like you would any other component.

Let's take a look at some code.

The goal here is to start out with some very basic code, then slowly add routing functionality to it. Here's our starting code.

```js
import React, { Component } from 'react'

class App extends Component {
  render() {
    return (
      <div>
        React Router Course
      </div>
    )
  }
}

export default App
```

As I mentioned earlier, React Router v4 is "just components". So the first thing we'll need to do is import the ones we'll need.

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

A few things to note here. First, we're importing `BrowserRouter` and renaming it `Router`. That's not necessary, but it's pretty common. What `BrowserRouter` does is it allows React Router to pass the app's routing information down to any child component it needs (via context). So to make React Router work, you'll need to render `BrowserRouter` at the root of your application.

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

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          React Router Course
        </div>
      </Router>
    )
  }
}

export default App
```

Next we have `Route`. `Route` is both the backbone and the genius behind React Router v4. When the app's location matches a certain path, `Route` will render a specified component, when it doesn't, it will render null. So say for example we had a `Home` component that we wanted to render when our app was at the index path `/`. Our code would look something like this

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

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

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <Route path='/' component={Home} />
        </div>
      </Router>
    )
  }
}

export default App
```

With the code above, if were were at the index page (/), we would see the `Home` component. If we weren't, we wouldn't see anything (because `Route` would have rendered null).

Let's add a few more routes now.

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

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topics = () => (
  <div>
    <h2>Topics</h2>
  </div>
)

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <Route path='/' component={Home} />
          <Route path='/about' component={About} />
          <Route path='/topics' component={Topics} />
        </div>
      </Router>
    )
  }
}

export default App
```

Notice that if we want to add more routes to our app, we just render more `Route` components. Again, this may feel a little weird to your brain if you're coming from static based routers since we're literally rendering our routes. One thing that helped me was to remember `Route` is just a normal React component with a render method. That render method is either rendering the component or it's rendering null depending on if the path matches. So when we render multiple `Route` components like we're doing above, those will either render the component or just render null.

So far, so good. One caveat that you might not have seen from the above code is that right now if you run the app and you head to the `/about` path, you'll notice that both the `About` component and the `Home` component are rendered. This is because even though `/` doesn't match the location exactly, it's still considered a partial match so the `Home` component is rendered. To get around this, you simply need to add an `exact` prop to the `/` Route to specify that you only want it to match when the location matches exactly.

```js
<Route exact path='/' component={Home} />
```

Now that we're dynamically rendering UI based on the app's location, the next thing we need to do is have some way for the user to change the apps location. This is where the `Link` component comes into play. It's a simple component that allows the user to declaratively navigate around the app. Now, using `Link`, let's add a simple navbar to our app.

```js
render() {
  return (
    <Router>
      <div>
        <ul>
          <li><Link to='/'>Home</Link></li>
          <li><Link to='/about'>About</Link></li>
          <li><Link to='/topics'>Topics</Link></li>
        </ul>

        <Route path='/' component={Home} />
        <Route path='/about' component={About} />
        <Route path='/topics' component={Topics} />
      </div>
    </Router>
  )
}
```

At this point, we've covered the absolute fundamentals of React Router v4. We're dynamically changing the UI based on the location by rendering a few different `Route` components and we're able to change the location of our app by rendering a few different `Link` components. Let's go a little deeper and talk about nested routes. Nested routes were a fundamental aspect of previous versions of React Router and they continue to be today. The biggest difference is the way in which you go about creating nested routes now compared to previous versions of React Router. In previous, static versions, you'd just nest routes in your route config. Because React Router v4 is all about dynamic routing, you can't do that. However, in my opinion, nested routes with React Router v4 is much more intuitive than with previous versions. Again, the key is to forget what you knew previously.

Looking back at our example, what if we wanted the `Topics` component to render a nested navbar and some nested routes? The answer to that doesn't need to be complicated. Just like you would nest a div, you can nest `Route`s.

```js
const Topic = () => {
  <div>
    <h3>TOPIC</h3>
  </div>
}

const Topics = () => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`/topics/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`/topics/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`/topics/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`/topics/rendering`} component={Topic} />
    <Route path={`/topics/components`} component={Topic} />
    <Route path={`/topics/props-v-state`} component={Topic} />
  </div>
)
```

Now when the user navigates to `/topics`, they'll see a nested navbar and the UI will be dynamically changing - just like before - based on the location. The only difference is now we're rendering the navbar and the `Route`s inside of another component, which is also being rendered by React Router.

You may have noticed that we hard coded the URLs instead of dynamically creating them based on the current nested location we're on. When React Router renders a component, it passes that component three things: `match`, `location`, and `history`. In this example, what we want is `match.url` which will give us the current matched portion of the URL (in our example, `/topics`). So anywhere where we're hard coding `/topic` we can replace with `match.url`.

```js
const Topic = () => {
  <div>
    <h3>TOPIC</h3>
  </div>
}

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.url}/rendering`} component={Topic} />
    <Route path={`${match.url}/components`} component={Topic} />
    <Route path={`${match.url}/props-v-state`} component={Topic} />
  </div>
)
```

Another thing you may have noticed is that we're rendering three different `Route`s even though each are rendering the same component and the only difference is the nested URL. This is the perfect use case for using URL parameters.

```js
const Topics = ({ match }) => (
  <div>
    ...

    <Route path={`${match.url}/:topicId`} component={Topic} />
  </div>
)
```

Now when React Router renders the `Topic` component, because we're passed that `match` prop we talked about earlier, we're also passed the `topicId` under `match.params`.

```js
const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)
```

Now lastly, when we're at the `/topics` route, if a topic hasn't already been selected, we want to render some text that says "Please select a topic". We can make a component that renders that text or we can just use `Route`s `render` prop like so

```js
<Route exact path={match.url} render={() => (
  <h3>Please select a topic.</h3>
)}/>
```

That's it! Our final code now looks like this,

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

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.url}/:topicId`} component={Topic}/>
    <Route exact path={match.url} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/topics">Topics</Link></li>
          </ul>

          <hr/>

          <Route exact path="/" component={Home}/>
          <Route path="/about" component={About}/>
          <Route path="/topics" component={Topics}/>
        </div>
      </Router>
    )
  }
}

export default App
```

By utilizing a component based API, React Router v4 truly is a React router. I believe React will make you a better JavaScript developer and React Router v4 will make you a better React developer.


***

This was originally published at [TylerMcGinnis.com](https://tylermcginnis.com/react-router-philosophy-introduction/) and is part of their [React Router](https://tylermcginnis.com/courses/react-router/) course.