1

I'm trying to implement nested routing in my react app The routes in my root app.jsx file are defined like this.

    <>
      <Router>
        <DrawerContextProvider>
        <Appbar />
        <Switch>
          <Route exact path='/admin'>
            <Admin/>
          </Route>
          <Route path='/technician' component={Technician} />
          <Route path='/accountmanager' component={AccountManager} />
        </Switch>
        </DrawerContextProvider>
      </Router>
    </>

This is the code in my admin component

function Admin() {
    const classes = useStyles();
    const { open } = useContext(DrawerContext)
    const { url, path } = useRouteMatch();

    return (
        <>
            <SideMenu iconsandnames={iconsandnames} />
            <div>
                <main
                    className={clsx(classes.content, {
                        [classes.contentShift]: open,
                    })}
                >
                    <div className={classes.drawerHeader} />
                    <Switch>
                        <Route exact path={path} >
                            <Dashboard />
                        </Route>
                        <Route  path={`${path}/:id`} >
                            <Outlet />
                        </Route>
                    </Switch>
                </main>
            </div>
        </>
    )
}

function Outlet() {
    const { id } = useParams();
    console.log(id);

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

}

This is the code in my Side menu component

export default function MiniDrawer({ iconsandnames }, props) {
    const classes = useStyles();
    const theme = useTheme();
    const { url, path } = useRouteMatch();
    const { open, handleDrawerClose } = useContext(DrawerContext)


    return (
        <div >
            <Drawer
                variant="permanent"
                className={clsx(classes.drawer, {
                    [classes.drawerOpen]: open,
                    [classes.drawerClose]: !open,
                })}
                classes={{
                    paper: clsx({
                        [classes.drawerOpen]: open,
                        [classes.drawerClose]: !open,
                    }),
                }}
            >
                <div className={classes.toolbar}>
                    <IconButton onClick={handleDrawerClose}>
                        {theme.direction === 'rtl' ? <ChevronRightIcon /> : <ChevronLeftIcon />}
                    </IconButton>
                </div>
                <Divider />
                <List>
                    {iconsandnames.map((data) => (
                        data.text == "Home" ? (
                            <Link to={url}>
                            <ListItem button key={data.text} >
                                <ListItemIcon><Icon>{data.iconname}</Icon></ListItemIcon>
                                <ListItemText primary={data.text} />
                            </ListItem>
                        </Link>):
(                        <Link to={`${url}/${data.route}`}>
                            <ListItem button key={data.text} >
                                <ListItemIcon><Icon>{data.iconname}</Icon></ListItemIcon>
                                <ListItemText primary={data.text} />
                            </ListItem>
                        </Link>)
                    ))}
                </List>
            </Drawer>
        </div>
    );
}

this is the iconsandnames array I'm passing into the sidemenu

const iconsandnames = [
    {
        iconname: 'home',
        text: 'Home',
        route: 'home'
    },
    {
        iconname: 'rounded_corner',
        text: 'Projects',
        route: 'projects'
    },
    {
        iconname: 'account_box',
        text: 'Account managers',
        route: 'accountmanagers'
    },
    {
        iconname: 'build',
        text: 'Contractors',
        route: 'contractors'
    },
    {
        iconname: 'perm_identity',
        text: 'Clients',
        route: 'clients'
    },
    {
        iconname: 'work_outline',
        text: 'Work Orders',
        route: 'workorders'
    },
    {
        iconname: 'preview',
        text: 'Additional',
        route: 'additional'
    },
]

http://localhost:3000/admin shows me enter image description here

http://localhost:3000/admin/projects shows me enter image description here

ideally the sidemenu should not disappear when I switch the route but instead it is disappearing over here. Any ideas on what might be the problem and how can I solve it?

1
  • Try passing exact with path={${path}/:id} in Admin component Commented Jul 19, 2021 at 8:18

1 Answer 1

2

Issue

You are specifying the exact prop on the "/admin" path, so any nested routes can no longer be matched and rendered.

<Route exact path='/admin'>
  <Admin/>
</Route>

Admin

<Switch>
  <Route exact path={path} > // <-- can match
    <Dashboard />
  </Route>
  <Route  path={`${path}/:id`} > // <-- can't match
    <Outlet />
  </Route>
</Switch>

Solution

When rendering Route components into a Switch, path order and specificity matter. You will want to order your paths from more specific to less specific, in order to give the more specific paths a chance to be matched and rendered first before less specific paths.

Routes - remove the exact prop from the "/admin" route so any nested route can be matched.

<>
  <Router>
    <DrawerContextProvider>
    <Appbar />
    <Switch>
      <Route path='/admin'>
        <Admin/>
      </Route>
      <Route path='/technician' component={Technician} />
      <Route path='/accountmanager' component={AccountManager} />
    </Switch>
    </DrawerContextProvider>
  </Router>
</>

Admin - reorder the routes by specificity.

<Switch>
  <Route path={`${path}/:id`} >
    <Outlet />
  </Route>
  <Route path={path} >
    <Dashboard />
  </Route>
</Switch>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.