Search code examples
reactjsmaterial-uireact-routerreact-router-dom

How to use MUI Drawer in a separate .jsx file with BrowserRouter?


I have prepared a simple test case at Github for my question:

screenshot

In my App.jsx there is following code:

<NavDrawer />

<BrowserRouter>
  <Routes>
    <Route path="page1" element={<Page1 />} />
    <Route path="page2" element={<Page2 />} />
    <Route path="page3" element={<Page3 />} />
    <Route path="*" element={<Page4 />} />
  </Routes>
</BrowserRouter>

And in the NavDrawer.jsx I have the code:

const drawerLinks = [
  { text: "Page 1", path: "/page1", icon: <CarCrash /> },
  { text: "Page 2", path: "/page2", icon: <Help /> },
  { text: "Page 3", path: "/page3", icon: <Directions /> },
  { text: "Page 4", path: "/page4", icon: <CarRepair /> },
];

function MyListItem({ text, path, icon }) {
  return (
    <ListItem disablePadding>
      <ListItemButton>
        <ListItemIcon>{icon}</ListItemIcon>
        <Link to={path}>
          <ListItemText primary={text} />
        </Link>
      </ListItemButton>
    </ListItem>
  );
}

export default function NavDrawer() {
  return (
    <Drawer>
      <BrowserRouter>
        <nav>
          <List>
            {drawerLinks.map((item, index) => (
              <MyListItem key={index} icon={item.icon} text={item.text} />
            ))}
          </List>
        </nav>
      </BrowserRouter>
    </Drawer>
  );
}

Unfortunately, nothing happens when I click one of the Links in the Drawer, the displayed page stays the Page4 and there is no messages or errors printed in console.


Solution

  • The NavDrawer component is rendering its own BrowserRouter component completely separate from the BrowserRouter that App renders. The links clicked on in NavDrawer are handled by NavDrawer's router and the other main router is completely unaware of any navigation actions that were effected and handled.

    You need only one router per application, generally at or near the root level of the app.

    Remove BrowserRouter from NavDrawer and nest NavDrawer under the root BrowserRouter component so the one single router handles all navigation actions.

    export default function NavDrawer() {
      return (
        <Drawer>
          <nav>
            <List>
              {myLinks.map((item, index) => (
                <MyListItem key={index} icon={item.icon} text={item.text} />
              ))}
            </List>
          </nav>
        </Drawer>
      );
    }
    
    <BrowserRouter>
      <NavDrawer /> // <-- rendered within routing context
      <Routes>
        <Route path="page1" element={<Page1 />} />
        <Route path="page2" element={<Page2 />} />
        <Route path="page3" element={<Page3 />} />
        <Route path="*" element={<Page4 />} />
      </Routes>
    </BrowserRouter>