Why can I not nest Route components in react-router 4.x?

10,402

Solution 1

Forget what you know about React Router < v4. You nest routes by literally nesting <Routes>. Check this example. Specifically check out the Topics component. You don't declare your routes up front but instead dynamically when a component renders.

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

const BasicExample = () => (
  <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>
)

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

const About = () => (
  <div>
    <h2>About</h2>
  </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>

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

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

export default BasicExample

Solution 2

With react-router v4 and v5 you can also use the render prop to nest routes

<Route 
  path='/stuff' 
  render={({ match: { url } }) => (
    <>
      <Route path={`${url}/`} component={Stuff} exact />
      <Route path={`${url}/a`} component={StuffA} />
    </>
  )} 
/>

In my opinion this syntax ends up more readable in most situations, compared to splitting out the sub-routes into a separately defined component passed in through the component prop.

I posted a similar answer here but noticed this question also has a lot of views and so thought it would be helpful to port it here.

Share:
10,402

Related videos on Youtube

scniro
Author by

scniro

See you later, alligator.

Updated on September 16, 2022

Comments

  • scniro
    scniro over 1 year

    How in the world does one use nested routes in react-router, specifically, version 4.x? The following worked well in previous versions...

    <Route path='/stuff' component={Stuff}>
      <Route path='/stuff/a' component={StuffA} />
    </Route>
    

    Upgrading to 4.x throws the following warning...

    Warning: You should not use <Route> component and <Route children> in the same route; <Route children> will be ignored

    What in the heck is going on here? I've scoured the docs for hours and can not successfully get nested routes working. How does one use <Route>components to nest their routes in react-router v4? How does my simplistic example translate to v4.x API compliance to nest a route?

  • scniro
    scniro about 7 years
    Awesome thank you for a detailed answer. I'll get back to your tomorrow when I get as chance to check this out - but your example looks promising. I must say I am really disappointed with the api changes and will likely go without this library.
  • Tyler McGinnis
    Tyler McGinnis about 7 years
    No worries. Give V4 a chance. It'll feel a little weird at first, but there's a very good reason the API was changed to this. It's much more powerful and is "just components".
  • scniro
    scniro about 7 years
    I looked into this and it indeed works well. However, ran into more problems with my active class styling conflicting with children. After headdeaking for a good while, I started over with router5, which, comes with its own maddening baggage. Wish routing in react was stupid simple such as ui-router was in angular 1.x. Anyways, thank you!
  • Shawn Mclean
    Shawn Mclean about 7 years
    @scniro Thanks for pointing out router5, looking into that now. React-router messed up on even breadcrumbs and other dependencies we had.
  • Dimo
    Dimo over 6 years
    @TylerMcGinnis is it possible to nest a route like path={`${match.url}/:topicId/edit`} that will show a new page where you can edit the topic and which does not inherit layout from the TopicId?
  • PositiveGuy
    PositiveGuy over 6 years
    react-router v4 is terrible. It also couples your tests to the router . So even if your testing behavior that's not related to custom routes, your tests are forced to know about react-router as a dependency and you have to wrap your tests with MemoryRouter which is terrible. Leaky as hell and your tests become even less isolated and coupled to this crap
  • PositiveGuy
    PositiveGuy over 6 years
    that's a bad example let me update that. I have another that does not have that check, same setup and still works