kyle
kyle

Reputation: 527

How do you properly nest multiple routes with react-router 5

I can't seem to figure out what I'm doing wrong. Basically I have an admin header that navigates to /admin. There I want to have a link to travel to /admin/render and display a component there. However, nothing displays at /admin/render. What am I missing?

https://codesandbox.io/s/react-router-nesting-forked-zxp7w?file=/index.js:0-1807

import ReactDOM from "react-dom";
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams,
useRouteMatch
} from "react-router-dom";
import {
Grid,
AppBar,
Container,
IconButton,
List,
ListItem,
ListItemText,
Toolbar
} from "@material-ui/core";

ReactDOM.render(<NestingExample />, document.getElementById("root"));

export function NestingExample() {
return (
    <Router>
    <div>
        <Grid container>
        <Grid item xs={12}>
            <List>
            <ListItem component={Link} to="/admin">
                <ListItemText primary="Admin" />
            </ListItem>
            </List>
        </Grid>
        </Grid>
        <hr />

        <Switch>
        <Route exact path="/">
            <Home />
        </Route>
        <Route exact path="/admin" component={AdminLanding} />
        </Switch>
    </div>
    </Router>
);
}

function Home() {
return (
    <div>
    <h2>Home</h2>
    </div>
);
}

function AdminLanding() {
let { path, url } = useRouteMatch();

return (
    <Grid container>
    <Link to={`${url}/rendering`}>Rendering with React</Link>

    <Switch>
        <Route exact path={path}>
        <h3>Please select a topic.</h3>
        </Route>
        <Route path={`${path}/:topicId`}>
        <Topic />
        </Route>
    </Switch>
    </Grid>
);
}

function Topic() {
let { topicId } = useParams();

return (
    <div>
    <h3>{topicId}</h3>
    </div>
);
}

Upvotes: 1

Views: 301

Answers (1)

Drew Reese
Drew Reese

Reputation: 202721

Issue

The root route rendering your admin landing page is only rendered when the path is exactly "/admin".

<Route exact path="/admin" component={AdminLanding} />

Sub-routes will be excluded and not matched by the nested Switch since AdminLanding is no longer rendered.

Solution

Remove the exact prop so the nested Switch handles matching nested pages.

<Route path="/admin" component={AdminLanding} />

I suggest also inverting the order (or listing more specific paths before less specific paths) of the nested routes so they also don't need the exact prop.

<Switch>
  <Route path={`${path}/:topicId`}>
    <Topic />
  </Route>
  <Route path={path}>
    <h3>Please select a topic.</h3>
  </Route>
</Switch>

Note: It also seems that you really want the nested header to always be rendered since it will only render the h3 when not matched by any other path. Maybe this is just a simplified code example though. If not then it should probably be pulled and rendered before the Switch.

Upvotes: 2

Related Questions