Home > OS >  How to place protected routes within an array in React.js?
How to place protected routes within an array in React.js?

Time:08-16

I'm hoping to set up protected routes for my webapp built with React.js. I have an array 'menuOptions' that I have been looping through to add options to my navbar. However, I've now been running in to issues as I would like to add protected routes.

So for instance, I would like to have Home, Login and Register when the user is logged out, and Dashboard and Logout as the options for when the user is logged in. I'd really appreciate any help. Ideally, I'd somehow add the '!user' to the menuOptions array somehow.

My code is below (as you can see menuOptions does not do anything for the above at the moment):

import React, { useState, useContext } from "react";
import { Link, NavLink, useNavigate } from "react-router-dom";
import { useAuthState } from "react-firebase-hooks/auth";
import { auth, logout } from "../../firebase";
import { makeStyles } from "@material-ui/core/styles";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import Typography from "@material-ui/core/Typography";
import IconButton from "@material-ui/core/IconButton";
import MenuIcon from "@material-ui/icons/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/Menu";
import { useTheme } from "@material-ui/core/styles";
import useMediaQuery from "@material-ui/core/useMediaQuery";

const useStyles = makeStyles((theme) => ({
  title: {
    flexGrow: 1,
  },
  appbar: {
    // background: 'none',
  },
  inactiveLink: {
    color: "white",
    padding: theme.spacing(1),
    fontSize: "1.5rem",
  },
  activeLink: {
    color: "black",
    padding: theme.spacing(1),
    fontSize: "1.5rem",
    background: "#bfbfbf",
  },
}));

function Navigation() {
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = useState(null);
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down("md"));

  const open = Boolean(anchorEl);
  const menuOptions = [
    { label: "Home", path: "/",  },
    { label: "Register", path: "/register" },
    { label: "Dashboard", path: "/dashboard" },
    { label: "Logout", path: "/logout" },
  ];

  const handleMenuSelect = (pageURL) => {
    navigate(pageURL);
  };

  const handleMenu = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const [user] = useAuthState(auth);
  const navigate = useNavigate();
  return (
    <>
      <AppBar
        className={classes.appbar}
        position="fixed"
        elevation={0}
        color="primary"
      >
        <Toolbar>
          <Typography variant="h4" className={classes.title}>
            The Football App
          </Typography>
          <Typography variant="h6" className={classes.title}>
            All you ever wanted to know about Football!
          </Typography>
          {isMobile ? (
            <>
              <IconButton
                aria-label="menu"
                aria-controls="menu-appbar"
                aria-haspopup="true"
                onClick={handleMenu}
                color="inherit"
              >
                <MenuIcon />
              </IconButton>
              <Menu
                id="menu-appbar"
                anchorEl={anchorEl}
                anchorOrigin={{
                  vertical: "top",
                  horizontal: "right",
                }}
                keepMounted
                transformOrigin={{
                  vertical: "top",
                  horizontal: "right",
                }}
                open={open}
                onClose={() => setAnchorEl(null)}
              >
                {menuOptions.map((opt) => (
                  <MenuItem
                    key={opt.label}
                    onClick={() => handleMenuSelect(opt.path)}
                  >
                    {opt.label}
                  </MenuItem>
                ))}
              </Menu>
            </>
          ) : (
            <>
              <nav>
                <div>
                  {!user ? (
                    <NavLink
                      to="/"
                      className={({ isActive }) =>
                        isActive
                      }
                    >
                      Home
                    </NavLink>
                  ) : (
                    <NavLink
                      to="/dashboard"
                      className={({ isActive }) =>
                        isActive
                      }
                    >
                      Dashboard
                    </NavLink>
                  )}
                </div>
                {!user ? (
                  <div>
                    <Link to="/login">
                      <a>Login</a>
                    </Link>
                    <Link to="/register">
                      <a>Register</a>
                    </Link>
                    </div>
                ) : (
                  <div className="navbar-end">
                    <Link to="/logout">
                      <a>Log Out</a>
                    </Link>
                  </div>
                )}
              </nav>
            </>
          )}
        </Toolbar>
      </AppBar>
    </>
  );
}

export default Navigation;

CodePudding user response:

You could update your menuOptions object to include a protected key:

const menuOptions = [
    { label: "Home", path: "/", protected:  false },
    { label: "Register", path: "/register", protected:  false },
    { label: "Dashboard", path: "/dashboard", protected:  false },
    { label: "Logout", path: "/logout", protected:  true },
  ];

and update the logic where your render your menu options to something like

{menuOptions.map((opt) => {
  if (opt.protected && !user) return;
  return (
    <MenuItem
      key={opt.label}
      onClick={() => handleMenuSelect(opt.path)}
    >
      {opt.label}
    </MenuItem>
  );
}
)}
  • Related