54

I need multiple nested routes in react-router-dom

I am using v4 of react-router-dom

I've got my

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

and I need the components to render like so

--- Login
--- Home
    --- Page 1
    --- Page 2
    --- Page 3
--- About
--- etc

The Home component contains a Header component that is common to Page1, Page2, and, Page3 components, but is not present in Login and About.

My js code reads like so

<Router>
    <div>
        <Route path='/login' component={Login} />
        <Home>
            <Route path='/page1' component={Page1} />
            <Route path='/page2' component={Page2} />
            <Route path='/page3' component={Page3} />
        </Home>
        <Route path='/about' component={About} />
    </div>
</Router>

I expect the Login component to show only on /login When I request for /page1, /page2, /page3, they should contain the Home component and that page's content respectively.

What I get instead is the Login component rendered and below that Page1's component is rendered.

I'm pretty sure that I'm missing something very trivial or making a really silly mistake somewhere, and would appreciate all the help I could get. I've been stuck with this for the last two days.

Aditya Talpade
  • 713
  • 1
  • 7
  • 13
  • you need to add `exact` props on the Route that needs to show on the exact match. – Rei Dien Mar 23 '17 at 22:50
  • 1
    Tried exact with /login, but my Home component shows up under my Login component. – Aditya Talpade Mar 24 '17 at 03:33
  • @AdityaTalpade check my answare as well – Umair Ahmed Apr 05 '17 at 21:15
  • 1
    Hey Aditya, are you able to do this thing? I also wanted to do the exact same thing. In my scenario, when the user opens up the website react will redirect it to the login if the user is not logged in. After login, my index page shows up with nav bar and search bar. Now I wanted to show rest of the pages in the body this index page so that all pages will share the same nav bar and search bar. I would appreciate a lot if you can help me. – Nishank Singla Apr 25 '17 at 17:46
  • 4
    No. I gave it up. Went with react router v3. My workflow was terribly hampered dealing with v4 which wasn't worth the extra effort. – Aditya Talpade Apr 26 '17 at 20:19
  • Once you use React 16, you'll need to make the switch to React Router 4 – zeckdude Jun 01 '18 at 22:09

6 Answers6

70

Use the url/path match obtained from props this.props.match.path to get the path that is set to a component.

Define your main routes as below

<Router>
  <div>
    <Route exact path="/" component={DummyIndex} /> {/* Note-1 */}
    <Route path="/login" component={Login} />
    <Route path="/home" component={Home} />
    <Route path="/about" component={About} />
    <Route path="/etc" component={Etc} />
  </div>
</Router>

Then in Home Component, define your routes

class Home extends Component {
  render() {
    return <div>
      <Route exact path={this.props.match.path} component={HomeDefault} />
      <Route path={`${this.props.match.path}/one`} component={HomePageOne} />
      <Route path={`${this.props.match.path}/two`} component={HomePageTwo} />
    </div>
  }
}

The defined routes are as below

  • /login
  • /home
  • /home/one
  • /home/two
  • /about
  • /etc

If you want to nest routes further in HomePageOne like /home/one/a and /home/one/b, you can proceed the same approach.

Note-1: If you don't want further nesting, just set the route with prop exact.

EDIT (May 15, 2017)

Initially, I've used props.match.url and now I changed it to props.match.path.

We can use props.match.path instead of props.match.url in Route's path so that if you use path params in top level routes, you can get it in inner (nested) routes via props.match.params.

If you don't you any path params, props.match.url is enough

Ram Babu
  • 1,849
  • 3
  • 21
  • 27
  • 2
    Im getting `TypeError: Cannot read property 'path' of undefined` – Ashish Kamble Aug 13 '19 at 12:37
  • one comment: instead of using
    , i use to avoid unnecessary html tags.
    – xiongemi Nov 17 '19 at 21:13
  • @AshishKamble if you receive `Cannot read property 'path' of undefined`, it means the props `match` is undefined. Make sure that you assign right component to the prop named "component" in Route – Ram Babu Nov 18 '19 at 03:29
  • @xiongemi you're right. you can use `` but it has a purpose, make sure that you know it. – Ram Babu Nov 18 '19 at 03:32
  • To get rid of Cannot read property 'path' of undefined error, you need to pass the props in argument: (props) => props.match.match.url – Artur Stary May 20 '20 at 19:29
26

Use Switch component in router v4

<Router>
<Switch>
  <Route path='/login' component={Login} />
  <Route path='/about' component={About} />
  <Home>
    <Route component={({ match }) =>
      <div>
        <Route path='/page1' component={Page1} />
        <Route path='/page2' component={Page2} />
        <Route path='/page3' component={Page3} />
      </div>
    }/>
  </Home>
</Switch>

export default class Home extends Component {
render() {
    return (
      <div className="Home">
          { this.props.children }
      </div>
    )
  }
}

I think this code shows the basic idea of using component.

Igor Stetsiura
  • 775
  • 6
  • 14
5

This week I had the same problem, I think the project is passing for time of confusion because all the documentation, examples and videos are for the previous versions and the docs for the version 4 are confusing
This is how I get the things done, let me know if this help

import React, { Component } from 'react';

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

import Root from './Root';
import Home from './Home';
import About from './About';

import './App.css';

class App extends Component {
    render() {
        return (
            <BrowserRouter>
                <div>
                    <Root>
                       <Switch>
                            <Route exact path="/" component={Home} />
                            <Route path="/home" component={Home} />
                            <Route path="/about" component={About} />
                        </Switch>
                    </Root>
                </div>
            </BrowserRouter>
        );
    }
}

export default App;
Mirdrack
  • 678
  • 8
  • 22
2

Move all childs routes to parent component and extend route like below.
<Route path={`${match.url}/keyword`} component={Topic}/>
also check react router training

Umair Ahmed
  • 5,537
  • 2
  • 25
  • 32
1

Use Like the following:

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <Link to='/create'> Create </Link>
        <Link to='/ExpenseDashboard'> Expense Dashboard </Link>
        <Switch>
          <Route path='/ExpenseDashboard' component={ExpenseDashboard} />
          <Route path='/create' component={AddExpensePage} />
          <Route path='/Edit' component={EditPage} />
          <Route path='/Help' component={HelpPage} />
          <Route component={NoMatch} />
        </Switch>
      </BrowserRouter>
    );
  }
}

See more @ Switch on GitHub

Mushfiq
  • 713
  • 1
  • 8
  • 37
0

I had the same problem and I solved it like this

<BrowserRouter>
          <UserAuthProvider>
            <Root>
              <Switch>
                <GuardRoute type="public" exact path="/" component={Login} />
                <GuardRoute type="private" exact path="/home" component={Home} />
                <GuardRoute
                  type="private"
                  exact
                  path="/home/mascotas"
                  component={Mascotas}
                />

              </Switch>
            </Root>
          </UserAuthProvider>
        </BrowserRouter>
Yosef Tukachinsky
  • 4,839
  • 7
  • 26
  • 2
    English is the language used on Stack Overflow. There are some Stack Exchange sites that are in other languages, but this one has a single language. – Jason Aller Jun 14 '20 at 17:02