javascriptreactjsreact-routerreact-router-dom

How to make sidebar available for all components?


I am using react router dom v6 and want to implement a logic where the sidebar will be available across all the components in my. Currently whenever i try to click any in side bar the side bar is vanishing. I want to keep the side bar across all the components in my app.

Side Bar available

Sidebar gone

Index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';

    import {BrowserRouter as Router,    Routes, Route,Navigate,Link} from
   'react-router-dom'; import Login from
   '../src/components/Login/LoginPage'; import Test from
   '../src/components/test/Test'; import Homepage from
   '../src/components/homepage/HomePage'; import Scheduler from
   '../src/components/scheduler/Scheduler'; import Classroom from
   '../src/components/classroom/Classroom'; import Assignment from
   '../src/components/assignment/Assignment'; import Meeting from
   '../src/components/meetings/Meetings'; import ReportCard from
   '../src/components/reportcard/ReportCard'; import SideMenuBar from
   '../src/components/sidemenubar/SideMenuBar'; ReactDOM.render(

    <Router>
      <Routes>
        <Route path='/' element={<Login />} />
        <Route path='/api/v1/testpath' element={<Test />} />
        {/* Sidebar Routes */}
        <Route path="/api/v1/app/userHome" exact element={<Test />} />
        <Route path="/api/v1/app/schedule" exact element={<Scheduler />} />
        <Route path="/api/v1/app/myclassroom" exact element={<Classroom />} />
        <Route
          path="/api/v1/app/myassignments"
          exact
          element={<Assignment />}
        />
        <Route path="/api/v1/app/mymeetings" exact element={<Meeting />} />
        <Route path="/api/v1/app/viewreports" exact element={<ReportCard />} />
      </Routes>
    </Router>,


  document.getElementById('root')
);

Sidebar.js

import {
  ListItemIcon,
  ListItemText,
  List,
  Divider,
  Drawer,
  Avatar,
  Box,
  ListItemButton,
} from "@mui/material";
import { makeStyles } from "@mui/styles";

import HomeIcon from "@mui/icons-material/Home";
import WatchLaterIcon from "@mui/icons-material/WatchLater";
import GroupsIcon from "@mui/icons-material/Groups";
import AssignmentOutlinedIcon from "@mui/icons-material/AssignmentOutlined";
import AssessmentOutlinedIcon from "@mui/icons-material/AssessmentOutlined";
import LogoutOutlinedIcon from "@mui/icons-material/LogoutOutlined";
import MeetingRoomOutlinedIcon from "@mui/icons-material/MeetingRoomOutlined";

import Logo from "./logo.png";

import { BrowserRouter as Router, Route, Link, Routes } from "react-router-dom";
import Homepage from "../homepage/HomePage";
import Scheduler from "../scheduler/Scheduler";
import Classroom from "../classroom/Classroom";
import Assignment from "../assignment/Assignment";
import ReportCard from "../reportcard/ReportCard";
import Meeting from "../meetings/Meetings";
const drawerWidth = 350;
const useStyles = makeStyles({
  page: {
    background: "#f9f9f9",
    width: "100%",
  },
  root: {
    display: "flex",
  },
  drawer: {
    width: drawerWidth,
  },
  drawerPaper: {
    width: drawerWidth,
    borderRadius: "2%",
  },
  listitem: {
    "&:hover": {
      fontWeight: "fontWeightBold",
      background: "#f9f9f9",
    },
  },
  navlink: {
    textDecoration: "inherit",
    color: "inherit",
  },
});

export default function Sidemenubar() {
  const classes = useStyles();

  return (
    <Box sx={{ display: "flex" }}>
      <Divider />

      <Drawer
        className={classes.drawer}
        variant="permanent"
        classes={{ paper: classes.drawerPaper }}
        anchor="left"
      >
        {/*App Logo */}
        <Avatar
          src={Logo}
          alt="404"
          sx={{ width: 100, height: 100, alignSelf: "center", margin: 1 }}
        />
        {/*Menu Items */}

        <List component="nav">
          <Link to="/api/v1/app/userHome" className={classes.navlink}>
            <ListItemButton
              sx={{
                "&:hover": {
                  fontWeight: "bold",
                  boxShadow: 1,
                  background: "#6D62DA",
                },
              }}
            >
              <ListItemIcon>
                <HomeIcon />
              </ListItemIcon>
              <ListItemText primary="Home" />
            </ListItemButton>
          </Link>
          <Divider />
          <Link to="/api/v1/app/schedule" className={classes.navlink}>
            <ListItemButton
              sx={{
                "&:hover": {
                  fontWeight: "bold",
                  boxShadow: 1,
                  background: "#6D62DA",
                },
              }}
            >
              <ListItemIcon>
                <WatchLaterIcon />
              </ListItemIcon>
              <ListItemText primary="Scheduler" />
            </ListItemButton>
          </Link>
          <Divider />
        </List>
      </Drawer>
      <Routes>
      <Route path='/api/v1/app/userHome' element={<Homepage />}></Route>
        <Route path='/api/v1/app/schedule' element={<Scheduler />}></Route>
      </Routes>
    </Box>
  );
}

HomePage.js

import React from 'react';
import { Grid } from "@mui/material";
import SideMenuBar from '../sidemenubar/SideMenuBar';
import HomePage from '../homepage/HomePage';
import Scheduler from '../scheduler/Scheduler';
import {BrowserRouter as Router, 
    Routes, Route,Navigate,Link} from 'react-router-dom';
class Test extends React.Component{
    render(){
        return (
            <Grid container>
                <Grid item md={4}>
                    <SideMenuBar />
                </Grid>
                
                <Grid item md={8}>
                    <HomePage />
                </Grid>
                
            </Grid>
        )
    }
}

export default Test;

Solution

  • If you want to render a sidebar on every route/page then I suggest:

    Using Layout Wrapper Component and Outlet

    Create a layout container component that renders the Sidebar component and an Outlet into the respective grid columns. Render the page routes nested into the layout.

    import { Outlet } from 'react-router-dom';
    import SideMenuBar from '../sidemenubar/SideMenuBar';
    
    const PageLayout = () => (
      <Grid container>
        <Grid item md={4}>
          <SideMenuBar />
        </Grid>    
        <Grid item md={8}>
          <Outlet /> // <-- nested routes rendered here
        </Grid>     
      </Grid>
    );
    

    index.js

    <Router>
      <Routes>
        <Route path="/" element={<PageLayout />} >
          <Route index element={<Login />} />
          <Route path="/api/v1/app/userHome" element={<UserHome />} />
          <Route path="/api/v1/app/schedule" element={<Scheduler />} />
          <Route path="/api/v1/app/myclassroom" element={<Classroom />} />
          <Route
            path="/api/v1/app/myassignments"
            element={<Assignment />}
          />
          <Route path="/api/v1/app/mymeetings" element={<Meeting />} />
          <Route path="/api/v1/app/viewreports" element={<ReportCard />} />
        </Route>
      </Routes>
    </Router>
    

    Using Wrapper Component and children Prop

    An alternative would be to have the PageLayout component render its children instead, and wrap the Routes component.

    const PageLayout = ({ children }) => (
      <Grid container>
        <Grid item md={4}>
          <SideMenuBar />
        </Grid>    
        <Grid item md={8}>
          {children}
        </Grid>     
      </Grid>
    );
    

    index.js

    <Router>
      <PageLayout>
        <Routes>
          <Route path="/ element={<Login />} />
          <Route path="/api/v1/app/userHome" element={<UserHome />} />
          <Route path="/api/v1/app/schedule" element={<Scheduler />} />
          <Route path="/api/v1/app/myclassroom" element={<Classroom />} />
          <Route
            path="/api/v1/app/myassignments"
            element={<Assignment />}
          />
          <Route path="/api/v1/app/mymeetings" element={<Meeting />} />
          <Route path="/api/v1/app/viewreports" element={<ReportCard />} />
        </Routes>
      </PageLayout>
    </Router>