Intro to react-router
Tags: react, javascript, webdev, library
Published: 2019-12-04 09:23:02

### What we'll cover:

- [What is react-router?](#what)
- [Installation & setup](#setup)
- [Route component](#route)
- [Inline rendering](#inline)
- [Multiple paths](#multiple)
- [Link & NavLink components](#link)
- [Dynamic routes](#dynamic)
- [Switch component](#switch)
- [Redirect component / Protected Routes](#redirect)

Feel free to click and go right to the part you want.

**Let's jump right into it!** 😄

---

<h3 id="what">What is react-router?</h3>

React-router is a routing solution designed specifically for React.js. The whole idea is to help you keep your user interface in sync with the URL.

In other words, react-router makes rendering different components when you hit different URLs relatively easy and also gives you control over the navigation of your app.

---

<h3 id="setup">Installation & setup</h3>

Unlike other frameworks/libraries such as Angular which has a routing solution included out of the box, react-router is separate from the react.js library and you'll need to install it whenever needed.

Installation command:

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

#### Setup

As for the setup, it's quite easy. You'd wanna wrap your **App** component with the **BrowserRouter** component provided by react-router-dom.

If you're using the **create-react-app** starter configuration, then head to your **index.js** in the **src** folder.

Import:

```jsx
import { BrowserRouter } from "react-router-dom"
```

Then, wrap your `<App />` with the **BrowserRouter** like so:

```jsx
ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,

  document.getElementById("root")
)
```

This will enable routing across your app and will allow you to use the rest of the components provided by react-router-dom.

Now let's explore the first component on our list... 🧐

---

<h3 id="route">Route component</h3>

This component allows you to render a specific component **only** when you hit a **specific URL.** Also, it passes down an object as props containing useful information relevant to the component it's rendering.

We'll be taking a look at this object shortly.

To use the Route component, you'll need to import it:

```js
import { Route } from "react-router-dom"
```

#### Route component takes **4 main props**:

- **path** - On which route should the component render?
- **component** - Which component should be rendered on that path?
- **exact** - Should the component be rendered exactly on that path? or also on similar paths?
- **render** - Used instead of **component** prop to render inline components - we'll see an example in a moment

#### Example

```jsx
// App.js

import React from "react"
import Nav from "./components/Nav"
import Home from "./components/Home"
import About from "./components/About"

import { Route } from "react-router-dom"

function App() {
  return (
    <div className="App">
      <Nav />
      <Route path="/" exact component={Home} />
      <Route path="/about" exact component={About} />
    </div>
  )
}

export default App
```

#### Explanation

`<Nav />` : Will always appear on every route since it's not rendered by a `<Route />` component.

`<Route path="/" exact component={Home} />` : Will only show the Home component on the **"/"** path which is **localhost:3000** in this case.

`<Route path="/about" exact component={About} />` : Will only show the About component on the **"/about"** path which is **localhost:3000/about** in this case.

If we don't use **exact**, Home will always appear, even on **localhost:3000/about**. The reason is **"/about"** also has a **"/"** included in it. So we add **exact** to prevent this behavior.

We mentioned that there are 4 main props and we only covered 3 so far. That brings us to the **render** prop...

---

<h3 id="inline">Inline rendering</h3>

You might be asking, what if I want to pass down custom props to my components?

Since you can't specify any props to your components using the way we just explored using **component** prop. React-router has another prop called **render**.

Let's check out an example...

#### Example

```jsx
// App.js

import Home from "./components/Home"
import About from "./components/About"

import { Route } from "react-router-dom"

function App() {
  return (
    <div className="App">
      <Nav />

      <Route
        path="/"
        exact
        render={() => {
          return (
            <div>
              <h1>Home</h1>
              <p>welcome to my homepage</p>
            </div>
          )
        }}
      />

      <Route
        path="/about"
        exact
        render={<About text="This is my text that I want to pass down" />}
      />
    </div>
  )
}
```

#### Explanation

Using **render** instead of **component** will allow you to either write components inline like in the **Home** Route and also write a component tag with any props this component is expecting.

> **Note:** Using **render** will result in React unmounting and mounting the inline component again on every render, instead of just updating the existing component.

---

<h3 id="multiple">Multiple paths</h3>

If you wish to render the same component on the several routes, you can by specifying your **path** as a **regular expression string:**

```jsx
<Route path="/(home|users|contact)/" component={Home} />
```

---

<h3 id="link">Link & NavLink components</h3>

You don't want your users to go type every route into the URL to go to a page. This is where the **Link** and **NavLink** components come in.

You can wrap some text or other components with a **Link** or a **NavLink** and specify where it should take the users when they click on it.

**Import:**

```js
import { Link } from "react-router-dom"
```

#### Example

```jsx
     <Link to=”/contact>Contact</Link>
```

#### Explanation

Now when the users click on "Contact" they'll be taken to the specified route in the **to="..."** prop. This could be used in your Navbar component for example.

If you're using your localhost:3000, then, this link will take you to **localhost:3000/contact**.

What if you'd like to **add a specific style** only on the current link that you're currently on?

Use **NavLink** instead:

**Import:**

```js
import { NavLink } from "react-router-dom"
```

#### Example

```jsx
<NavLink to="/dashboard" activeClassName="selectedLink">
  Dashboard
</NavLink>
```

#### Explanation

By adding **" activeClassName="selectedLink" "**, now you can add some styles to the class **selectedLink** and they will be applied **only** to that link when the user is on the route **/dashboard**.

---

<h3 id="dynamic">Dynamic routes</h3>

When a component is routed by the react-router library, each route is provided with an object of information about that route and it's passed down to the component as props.

If you go into the file of a component routed by the `<Route />` and add props to the component then **console.log(props)**, you'll get the entire object logged.

#### Example

```jsx
export default function Contact(props) {
  console.log(props)

  return (
    <div>
      <h1>Contact component</h1>
    </div>
  )
}
```

#### Output

```js
// @ localhost:3000/contact
// Browser console output

Object

    history:
        action: "POP"
        block: ƒ block(prompt)
        createHref: ƒ createHref(location)
        go: ƒ go(n)
        goBack: ƒ goBack()
        goForward: ƒ goForward()
        length: 4
        listen: ƒ listen(listener)
        location: {pathname: "/contact", search: "", hash: "", state: undefined}
        push: ƒ push(path, state)
        replace: ƒ replace(path, state)
        __proto__: Object

    location:
        hash: ""
        pathname: "/contact"
        search: ""
        state: undefined
        __proto__: Object

    match:
        isExact: true
        params: {}
        path: "/contact"
        url: "/contact"

    __proto__: Object
    staticContext: undefined
    __proto__: Object
```

You'll see all this information specific to the **/contact** route, which could be accessed in the component to make it more dynamic.

Unfortunately, we won't be exploring all of those in this blog but, you can experiment with them as much as you like. The idea is to let you know they exist and that you can use them. 😊

We'll be exploring the **params** object located in **match**.

```js
// @ localhost:3000/contact
// Browser console output

    match:
        isExact: true
        params: {} 👈
        path: "/contact"
        url: "/contact"

```

Let's set up a route with a param then access it from within the component.

#### Example

```jsx
// App.js

function App() {
  return (
    <div className="App">
      <Nav />
      <Route path="/" exact component={Home} />
      <Route path="/contact" exact component={Contact} />
      <Route path="/user/:user" exact component={User} /> // New route
    </div>
  )
}
```

#### Explanation

You might be wondering what is that **:user**, this is called a **parameter** or **param** for short.

To put it in simple words, just think of it as a placeholder which it's value could be set only in the URL.

For example: if we visit **localhost:3000/user/someone**. The param will be set to the string **"someone"** and the same applies if you add anything in the place of **:user**.

You simply choose the value by visiting **localhost:3000/user/ANYTHING_HERE**

Now let's use that value in the **user** component:

#### Example

```jsx
// User.js

export default function User(props) {
  return (
    <div>
      <h1>Hello {props.match.params.user}</h1>
    </div>
  )
}
```

#### Explanation

`{props.match.params.user}` : This is accessing the value of the created ( **user** param ) since we named it **:user**.

Now if you visit **localhost:3000/user/your_name** you'll see **Hello your_name**, the same applies for any other string.

#### Please note:

This object is passed down automatically **ONLY** if you render your component using the **component={...}** **NOT** **render={...}**.

If you wish to pass down the same props using the **render={...}** prop, you can do it like so:

```jsx
// App.js

function App() {
  return (
    <div className="App">
      <Nav />
      <Route path="/" exact component={Home} />
      // This way 👇
      <Route path="/contact" exact render={props => <Contact {...props} />} />
    </div>
  )
}
```

This way you're creating a component which is taking props, then, using **object destructuring** to pass the props to the components by adding **{...props}**.

---

<h3 id="switch">Switch component</h3>

The switch component could be used if you want nest routes and have the **first matched route** to be selected.

Let's see an example...

**Import:**

```js
import { Switch } from "react-router-dom"
```

#### Example

```jsx
// App.js

function App() {
  return (
    <Switch>
      <Route path="/about" component={About} />
      <Route path="/about/2" component={About} />
      <Route path="/" component={Home} />
    </Switch>
  )
}
```

#### Explanation

This will simply go through each route from **top to bottom** and check if it matches the current route in the URL, then, choose **the first** match it finds and renders it.

Yes, you can do it by adding **exact** instead of relying on order.

There might be a special use case in your app where you might need this, so now you know that this option exists.

Your app, your choice.😉

---

<h3 id="redirect">Redirect component / Protected Routes</h3>

This component is useful if you have some **routes that can't be accessed unless a specific condition is met.**

Simply rendering the **Redirect** component will **automatically** send you to a specific route.

One of the common use cases of the **Redirect** component is when you have a login system and we don't want the user to access some routes unless they're logged in.

Import:

```jsx
import { Redirect } from "react-router-dom"
```

#### Example

```jsx
// App.js

import React, { useState } from "react"
import Nav from "./components/Nav"
import Home from "./components/Home"
import About from "./components/About"
import Dashboard from "./components/Dashboard"

import { Route, Redirect, Link } from "react-router-dom"

function App() {

  // Simple boolean state
  const [loggedin, setLoggedin] = useState(false) // initialized as false

  const handleLogin = () => {
    setLoggedin(true) // Toggle loggedin state to true
  }

  return (
    <div className="App">
      <Nav />
      <Route path="/" exact component={Home} />
      <Route path="/about" exact component={About} />

      {// Simple protected route 👇}
      <Route
        path="/dashboard"
        exact
        render={() => (loggedin ? <Dashboard /> : <Redirect to="/" />)}
      />

      { // Changes the login state to true 👇}
      <button onClick={handleLogin}>Login</button>

      { // Takes you to /dashboard route 👇}
      <Link to="/dashboard">Dashboard</Link>
    </div>
  )
}

export default App
```

#### Explanation

Here we have a boolean state representing if the user is logged in or not, we also have a button which changes the state of loggedin to true and we have a link to take us to the /dashboard route.

We're using a **ternary operator** in the protected route saying:

if **loggedin** is **true**, then, render `<Dashboard />`, **otherwise**, render a `<Redirect to="/" />` component, which immediately **redirects** the user to the **"/"** route so that they can't access this route since they're not logged in.

---

#### Congratulations! 🎉

With this covered, you now know how to enable and use routing in your react app, as well as learned about the basic components that the react-router library provides.

#### Learned something new?

Share this post with someone who can benefit from too.😄

Have a great day! 😇