React router dom: Nested routes
Tags: react, reactrouterdom
Published: 2020-01-20 21:10:04

In this tutorial, we are going to build a nested route, or commonly called nested routing params.

If you prefer videos this is the [youtube video](https://youtu.be/gIMD83QSvNk)

I consider this tutorial an example of nested routing because it is on the API level. However for the sake of simplicity they are only defined as routing parameters within the scope of the what is declared in the App.js that this tutorial shows how to build. 

__Who is this tutorial for.__

This is for any one that has a list of information being displayed to a user, when a user clicks a specific item in the list, that item will display a new page only showcasing that item. 

__How it should be used.__

I highly recommend doing this tutorial. deleting what you did. checking how far you can get from memory. referencing the tutorial when you get stuck. Deleting the app after you finish until you can do nested routes from memory. 

I'm a huge advocate of memorizing how to code vs... reference, copy and paste, move on. 

Memorizing how to do basic pieces of functionality __will__ make you a faster dev in the long run. 

__Why nested routing is useful.__

Having the ability to display more information that a user clicks on in a dynamic way like this keeps your web sites more organized and therefore, scalable.

 This is also foundational for almost every e-commerce website, so knowing how to do this could mean the difference between you and your dream job as a developer, or the ability to make an online business.

__Why this can be hard.__

the reason why nested routes are tricky to learn is because you are representing 1 piece of information in two very different ways and they look very similar in the browser.

__Prerequisites__

knowledge of javascript and react. 

basic knowledge of command line to install npm packages. 

if you don't have npm installed on your computer, these commands work on mac or pc. you can get find out how [here](https://www.tutorialsteacher.com/nodejs/what-is-node-package-manager). 

a text editor, I'll be using vs-code. 


let us get started. Make a new react app. 

```bash
create-react-app nested-routes-exp
```

after it installs, cd into the project folder. 

```bash
cd nested-routes-exp
```

inside the root of the project directory, on the command-line, install react-router-dom.

```bash
npm i react-router-dom
```

open your project in your text editor of choice. This is how on the command-line with vs-code.

```bash
code .
```

the top section of your package.json file, _also in your root directory_,you should have a place that says react-router-dom inside the curly brackets for the dependencies section. 

```json

{
  "name": "nested-routes-exp",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.4.0",
    "@testing-library/user-event": "^7.2.1",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
// *you should have this below

    "react-router-dom": "^5.1.2",

// * you should have this above. 
    "react-scripts": "3.3.0"
  },

```

__NOTE:__ DO NOT change this file directly if it isn't there. run _npm i react-router-dom_ on the command line as shown above.

Now that we know that we know react-router-dom is installed, make sure that the whole app has access to this functionality. 

to do this...

1. Open the index.js file in your text editor. 

2. import {BrowserRouter} from "react-router-dom"

3. BrowserRouter is just a piece of context that you didn't make but imported instead. so wrap your <App/> in BrowserRouter so that you can access it down the component tree. 

The whole file should look like this. 


```javascript

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

//import BrowerRouter
import {BrowserRouter} from 'react-router-dom'

ReactDOM.render(
  
  //sandwich the App with some BrowserRouter bread
    <BrowserRouter>
      <App />
    </BrowserRouter>
, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

```

_index.js in the src folder._

To ensure that this worked, open your App.js and we will import the pieces of functionality we want from react-router-dom and console.log them. 

we are going to use {Route, Switch } from "react-router-dom" 

__Route__ gives us a way to declare components that appear when we type in a url.

__Switch__ gives the ability to customize which components will display. In this case, the list of things we want and then on the click event displaying that item from the list.  

The App.js should look something like this. 

```javascript

import React from 'react';
import logo from './logo.svg';
import './App.css';

// add imports 
import {Route, Switch} from 'react-router-dom'


//add props as an argument
function App(props) {

  console.log('route',Route)
 console.log('switch',Switch)

  return (
    <div className="App">
      
    </div>
  );
}

export default App;

```

now start this project on a local server. 

```bash 
npm start

```

if your App.js is like the one above and you inspect the page you should see 2 console logged functions along with a blank white screen.



 ![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/om2ue43qekmok5jp3t5n.png)

we know Route and Switch are here in the App.js to make sure we can use them lets make a Home.js and a NoMatch.js as a 404 page to see if we can get them to display separately. 

if you are using vscode, you can right-click the src folder and choose to make a new folder called components, then you can make and name the 2 files. 


make the skeleton of these two components. 

_Home.js_

```javascript
import React from 'react';

const Home = (props) => {
  return (
    <div>
      Home
    </div>
  );
};

export default Home;

```

_NoMatch.js_

```javascript
import React from 'react';

const NoMatch = (props) => {
  return (
    <div>
      Error 404
    </div>
  );
};

export default NoMatch;

```

import these components in your App.js

```javascript

import Home from "./components/Home"
import NoMatch from "./components/NoMatch"

```

add these components to the return on the App.js

```javascript
 return (
    <div className="App">
 //testing if they show up

      <Home />
      <NoMatch />

    </div>
  );

```

now we want to add Switch to get the functionality we want by adding the <Switch> inside the return

```javascript
 return (
    <div className="App">
      {/* add Switch notice that the no match component isn't rendering. */}
      <Switch>

        <Home />
        <NoMatch />

      </Switch>
    </div>
  );

```

we are only getting one component right now because Switch reads from top to bottom. 

lets add a route. 

there are two ways to do this, change your home component to look like this. 



```javascript
<Route exact path='/home'> <Home /> </Route>

```

this allows us to only render the home component when we type into the Url /home. give it a try 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/bnenm7vq4g2yreg8cgs4.png)

and if we don't designate a path we get a page not found. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/jlg4op8k3uld1du0trwd.png)

There are a few ways to define routes, another syntax is component={} prop for the route

```javascript
<Route path component={NoMatch} />

```

Now the only time any other component will show up besides the 404 page is when we define that path here in our App.js

Normally this would be your home page, but for demonstration purposes, I wanted to show how you explicitly define them any way you want. 

also, render is better than component because you can pass your own props along with render props. rProps for short.

now we are ready to map through a list on the home page. 

I will be using the starwars API to demonstrate. 

import {useEffect,  useState} on the Home.js like so...

```javascript
import React, {useEffect, useState} from 'react'

```

this means that we should install and import axios to make life a little easier. 

```bash
npm i axios

```

in the Home.js at the top. 

```javascript
import axios from 'axios'

```


inside the function make an array for the starwars characters 


```javascript
  const [characters, setCharacters] = useState([])

```

and a useEffect to handle the get request. 


```javascript

useEffect( () => {
    axios.get(`https://swapi.co/api/people`)
      .then(res => {
        console.log(res.data.results)
      })
  }, [])

```

This should give you 10 objects in the console.log

Set these objects to state by replacing the console.log with setCharacters.


```javascript
setCaracters(res.data.results)

```

now display the characters to the browser by mapping them in the return.


```javascript
Home: 
      {characters.map(character => {
        return <h1>{character.name}</h1>
      })}

``` 

cool almost there. 

Next objectives 


1. get the characters name to show up in the url by replacing h1 with a Link . 

2. make the link render a Character component.


import {Link} from react-router-dom

add the name link


```javascript
<Link to={'/' + character.name}>{character.name}</Link>

```

click a character and you should see there name appear in the URL.


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/jzzmafhhwrjoq9q1lndk.png)

Make a Character.js we are going to need a axios.get useEffect and useState in this component. 

We also need useParams from react router dom. so that we can get the names from the url. 

here is the skeleton. 


```javascript
import React, {useEffect, useState} from 'react';
import axios from 'axios'
import {useParams} from 'react-router-dom'

const Character = (props) => {
  return (
    <div>
      Character: 

    </div>
  );
};

export default Character;

```

Now let's make it so that this component shows up when we click a character by declaring that route in the App.js

Add this Route inside the Switch.


```javascript
<Route exact path='/:name'> <Character /> </Route>

```

It’s important to understand that if we were to write the path=“/people/:name” it would be an example of a nested Route, since it’s not it’s considered a routing parameter. 

Notice the path='/:name' the __:__ makes it so that we can have an id representing the name. 

We need access to a thing that react-router-dom provides called match from params
console.log(useParams()) in the Character.js


```javascript

console.log(useParams())
```

 Walk down the object so that the character's name is just a string and not a key-value pair. 

```javascript
console.log(useParmas().name)
```

the console.log save that string to a variable so that you can add it to the url. 

Note: react will throw an error if you try and call useParams directly in the useEffect. This means you must call useParams outside the useEffect. 

```javascript
const name = useParams().name
```

Make the useEffect and the useState 


```javascript
const [character, setCharacter] = useState([])


//above the return. 

```

Since we want a single character, useEffect has to do a couple things.

1. do a get request for a single character with a search. 

2. add that character to state. 

this is what that useEffect looks like. 

```javascript
useEffect( () => {
    axios.get(`https://swapi.co/api/people/? 
     search=${name}`)
      .then(res => {
        setCharacter(res.data.results)
      })
  }, [])

```

This is how you set up a search of an API by a click event with react-router-dom. 

Make the info about the character appear on the screen you can add anything you want but this is what I wanted to show for this tutorial.

Inside the return statement add the extra info you wanted to display. 


```javascript
return (
    <div>
        Character: 
        {character.map(char => {
          return <>
          <h1>{char.name}</h1>
            <p>eye color: {char.eye_color}</p>
            <p>hair color: {char.hair_color}</p>
            <p>birth year: {char.birth_year}</p>
            <p> gender: {char.gender}</p>
          </>
        })}
        <Link to='/home'>back to home</Link>
    </div>
  );

```

This is my end result. 


```javascript

import React, {useEffect, useState} from 'react';
import axios from 'axios'
import {Link, useParams} from 'react-router-dom'



const Character = (props) => {
  const [character, setCharacter] = useState([])

    const name = useParams().name

  console.log('character',character)
  useEffect( () => {
    axios.get(`https://swapi.co/api/people/?search=${name}`)
      .then(res => {
        setCharacter(res.data.results)
      })
  }, [])


  return (
    <div>
        Character: 
        {character.map(char => {
          return <>
          <h1>{char.name}</h1>
            <p>eye color: {char.eye_color}</p>
            <p>hair color: {char.hair_color}</p>
            <p>birth year: {char.birth_year}</p>
            <p> gender: {char.gender}</p>
          </>
        })}
        <Link to='/home'>back to home</Link>
    </div>
  );
};

export default Character;
```

That's it! I would suggest playing around and adding upon this tutorial to get the most out of it. 

the API is kind of slow but it might be cool to make your own back-end and database and see what you could do. 

I hope this tutorial was helpful. 

If there is anything you would like me to add or if there are errors to fix, any kind of feedback in general, add them to the comments below. 

[github](https://github.com/TallanGroberg/nested-routes-tutorial)

[other react tutorials](https://dev.to/tallangroberg)


Thanks so much for checking out my silly write up!!