Reputation: 404
I'm trying to implement a dynamic menu which changes its structure depending on the user role
See full code below:
import React, {
useState,
useLayoutEffect,
useEffect,
useCallback,
} from "react";
import { Drawer, IconButton, List, Avatar } from "@material-ui/core";
import {
Inbox as InboxIcon,
PresentToAll as PresentToAllIcon,
ListAlt as ListAltIcon,
Language as LanguageIcon,
Description as DescriptionIcon,
List as ListIcon,
Money as MoneyIcon,
Face as FaceIcon,
TransferWithinAStation as TransferWithinAStationIcon,
AttachMoney as AttachMoneyIcon,
PersonPinCircle as PersonPinCircleIcon,
Home as HomeIcon,
ArrowBack as ArrowBackIcon,
Edit as EditIcon,
AccountBalanceWallet,
PeopleAlt,
} from "@material-ui/icons";
import { useTheme } from "@material-ui/styles";
import { withRouter } from "react-router-dom";
import classNames from "classnames";
import useStyles from "./styles";
import SidebarLink from "./components/SidebarLink/SidebarLink";
import {
useLayoutState,
useLayoutDispatch,
toggleSidebar,
} from "../../context/LayoutContext";
import Dot from "./components/Dot";
import pesonetlogo from "../../images/test-logo.png";
import { USER_PROFILE_ID_SESSION_ATTRIBUTE } from "../../services/AuthenticationService";
import ProfileMaintenanceService from "../../services/ProfileMaintenanceService";
function Sidebar({ location }) {
var classes = useStyles();
var theme = useTheme();
var { isSidebarOpened, modules } = useLayoutState();
var layoutDispatch = useLayoutDispatch();
var [isPermanent, setPermanent] = useState(true);
// should be in UserContext for global state
const [profileDetails, setProfileDetails] = useState([]);
const [profileModules, setProfileModules] = useState([]);
// const [profileActions, setProfileActions] = useState([]);
var structureNew = [];
const profileList = sessionStorage.getItem(USER_PROFILE_ID_SESSION_ATTRIBUTE);
useEffect(() => {
modules.forEach((modulesMap, i) => {
structureNew[i] = structure.filter(
(structureFiltered) => structureFiltered.label == modulesMap
);
});
console.log("06262020 useEffect structureNew ", structureNew)
}, []);
// useLayoutEffect(() => {
// console.log("06252020 useEffect profileDetails ", profileDetails);
// const modules = profileDetails.map((module) => module.module);
// // const actions = profileDetails
// // .map((item) => item.actions.map((action) => action.action))
// // .flat();
// setProfileModules(profileModules.concat(modules));
// // setProfileActions(profileActions.concat(actions));
// }, [profileDetails]);
// useLayoutEffect(() => {
// console.log("06252020 useEffect profileModules ", profileModules);
// structureNew = structure.filter(
// (structureFiltered) => structureFiltered.label == "Inward"
// );
// console.log("06252020 structureNew ", structureNew);
// }, [profileModules]);
// // // should be in UserContext for global use
// const retrieveProfileDetails = useCallback(() => {
// const profileListArr = profileList.split(",");
// profileListArr.forEach((profileListArrMap) => {
// ProfileMaintenanceService.retrieveProfileDetails(profileListArrMap).then(
// // dapat makuha din menu?
// (response) => {
// console.log(
// "06252020 retrieveProfileDetails response.data ",
// response.data
// );
// setProfileDetails(response.data);
// }
// );
// });
// });
var structure = [
{ id: 0, label: "Dashboard", link: "/test/dashboard", icon: <HomeIcon /> },
{
id: 1,
label: "Test1",
link: "/test1",
icon: <InboxIcon />,
},
{
id: 2,
label: "Test2",
link: "/test2",
icon: <PresentToAllIcon />,
},
{ id: 3, type: "divider" },
{
id: 4,
label: "Test3",
link: "/test3",
icon: <ListAltIcon />,
children: [
{
label: "Test4",
link: "/test4",
icon: <LanguageIcon />,
},
{
label: "Test5",
link: "/test5",
icon: <ListIcon />,
},
],
},
{
id: 5,
label: "Test6",
link: "/test6",
icon: <DescriptionIcon />,
},
{
id: 6,
label: "Test7",
link: "/test7",
icon: <AccountBalanceWallet />,
children: [
{
label: "Test8",
link: "/test8",
icon: <FaceIcon />,
},
{
label: "Test9",
link: "/test9",
icon: <TransferWithinAStationIcon />,
},
{
label: "Test10",
link: "/test10",
icon: (
<Avatar alt="Pesonet" src={pesonetlogo} className={classes.small} />
),
},
{
label: "Test11",
link: "/test11",
icon: <PeopleAlt />,
},
],
},
{
id: 7,
label: "Test12",
link: "/test12",
icon: <EditIcon />,
},
];
useEffect(function() {
window.addEventListener("resize", handleWindowWidthChange);
handleWindowWidthChange();
return function cleanup() {
window.removeEventListener("resize", handleWindowWidthChange);
};
});
return (
<Drawer
variant={isPermanent ? "permanent" : "temporary"}
className={classNames(classes.drawer, {
[classes.drawerOpen]: isSidebarOpened,
[classes.drawerClose]: !isSidebarOpened,
})}
classes={{
paper: classNames({
[classes.drawerOpen]: isSidebarOpened,
[classes.drawerClose]: !isSidebarOpened,
}),
}}
open={isSidebarOpened}
>
<div className={classes.toolbar} />
<div className={classes.mobileBackButton}>
<IconButton onClick={() => toggleSidebar(layoutDispatch)}>
<ArrowBackIcon
classes={{
root: classNames(classes.headerIcon, classes.headerIconCollapse),
}}
/>
</IconButton>
</div>
<List className={classes.sidebarList}>
{structureNew.map((link) => (
<SidebarLink
key={link.id}
location={location}
isSidebarOpened={isSidebarOpened}
{...link}
/>
))}
</List>
</Drawer>
);
function handleWindowWidthChange() {
var windowWidth = window.innerWidth;
var breakpointWidth = theme.breakpoints.values.md;
var isSmallScreen = windowWidth < breakpointWidth;
if (isSmallScreen && isPermanent) {
setPermanent(false);
} else if (!isSmallScreen && !isPermanent) {
setPermanent(true);
}
}
}
export default withRouter(Sidebar);
As you can see, structureNew
contains the menus and submenus which is being formed in useEffect
after some array manipulations
However, my problem is the page gets rendered first and calls structureNew
. At this point, structureNew
is empty
I would like to have structureNew
formed first before rendering the page
Is there any way I can do this using hooks?
TIA
Upvotes: 0
Views: 516
Reputation: 278
I recommend adding a loader for example:
const [loading, setLoading] = useState(true)
then after doing your manipulation set loading to false:
setLoading(false)
and before your add return:
if(loading){
return(<LoaderComponent/>)
}
return(
//your main return
)
Upvotes: 1
Reputation: 76
Why don't you create a structureNew
as a State and you setStructureNew in that useEffect?
Upvotes: 1