'React JS - MUI How to fix problem with expand/collapse and open drawer
I have 2 problems in the code that I can't solve.
- The first is the opening sidebar menu. The menu opens but does not close. It should close either with a click outside or by clicking on a link. I pass the values to another file. The open state is passed correctly if it would not open. While toggleSlider is not passed saying, in the console log, undefined.
- The second problem is the sub-menu. Without the opening code of the sub-menu, it works. I can't get it to work and it gives me error on the handleClick event (ts(2304)).
Thanks in advance for the help.
AppBar_Top.tsx:
import React, { useState } from 'react';
import { AppBar, Box, IconButton, Link, Slide, Toolbar, Typography, useScrollTrigger } from '@mui/material/';
import MenuIcon from '@mui/icons-material/Menu';
import { makeStyles } from "@mui/styles";
import Account from './appbar/Account.tsx';
import SideBar from './appbar/Sidebar.tsx';
import './style.css';
const useStyles = makeStyles((theme) => {
return {
root: {
display: "flex"
},
appBar: {
boxShadow: 'none',
zIndex: 1,
backgroundColor: '#008',
background: 'linear-gradient(#004,#008)',
},
menuIcon: {
paddingRight: 4,
paddingLeft: 4,
color: 'white',
},
menuButtonIconClosed: {
/*transition: theme.transitions.create(
["transform"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}
),*/
transform: "rotate(0deg)",
},
menuButtonIconOpen: {
/*transition: theme.transitions.create(
["transform"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}
),*/
transform: "rotate(180deg)"
},
}
});
// hide top bar when scrolling
interface Props {
window?: () => Window;
children: React.ReactElement;
}
function HideOnScroll(props: Props) {
const { children, window } = props;
const trigger = useScrollTrigger({
target: window ? window() : undefined,
});
return (
<Slide appear={false} direction="down" in={!trigger}>
{children}
</Slide>
);
}
function AppBar_Top(props: Props) {
//const [openModule, setOpenModule] = React.useState(false);
const classes = useStyles();
// open sidebar > drawer
const [open, setOpen] = useState(false);
const toggleSlider = () => {
setOpen(!open);
};
return (
<>
<Box>
<HideOnScroll {...props}>
<AppBar id="navTop" position="fixed" color='inherit' className={classes.appBar}>
<Toolbar>
<Box sx={{ flexGrow: 1, display: { xs: 'flex', md: 'flex' } }}>
<IconButton
edge='start'
className={classes.menuIcon}
aria-label='menu'
onClick={toggleSlider}
>
<MenuIcon />
</IconButton>
<Link>
<img height="50px" src="./logo.svg" alt="logo" />
</Link>
<Typography variant="h6">
<div className="logoname-flex">
<div>
title
</div>
<div id="groupDescription">
subTitle
</div>
</div>
</Typography>
</Box>
<Box sx={{ flexGrow: 0 }}>
<Account />
</Box>
<SideBar open={open} onClose={toggleSlider} />
</Toolbar>
</AppBar>
</HideOnScroll>
</Box>
</>
);
}
export default AppBar_Top;
SideBar.tsx:
import React from 'react';
import { Avatar, Box, Collapse, Divider, Drawer, List, ListItem, ListItemButton, ListItemText, ListItemIcon } from '@mui/material/';
import { makeStyles } from "@mui/styles";
const useStyles = makeStyles((theme) => ({
drawer: {
top: '65px',
background: 'linear-gradient(#004, #008)',
},
menuSliderContainer: {
width: '250px',
background: 'linear-gradient(#004, #008)',
height: "100%",
},
avatar: {
margin: "0.5rem auto",
padding: "1rem",
/*width: theme.spacing(13),
height: theme.spacing(13),*/
width: '128px',
height: '128px',
},
listItem: {
color: "tan",
}
}));
const listItems = [
{
id: 1,
title: "home",
hidden: false,
open: false,
localize: "web.home",
subMenu: null,
},
{
id: 2,
title: "groups",
hidden: false,
open: false,
localize: "web.groups",
subMenu: [
{id: "1", name: "favorites", hidden: true, localize: "web.groups", to: "",},
{id: "2", name: "create", hidden: false, localize: "web.create", to: "",},
{id: "3", name: "featured", hidden: false, localize: "web.featured", to: "",},
]
},
{
id: 3,
title: "customize",
hidden: false,
open: false,
localize: "web.customize",
subMenu: [
{id: "1", name: "embed", hidden: false, localize: "web.embed", to: "",},
{id: "2", name: "events", hidden: false, localize: "web.events", to: "",},
{id: "3", name: "customize", hidden: false, localize: "web.customize", to: "",},
]
},
{
id: 4,
title: "contacts",
hidden: false,
open: false,
localize: "web.contacts",
subMenu: null,
},
{
id: 5,
title: "search",
hidden: false,
open: false,
localize: "web.search",
subMenu: null,
},
];
//({ open }) ({ toggleSlider })
export default function Sidebar({open, toggleSlider}) {
const classes = useStyles();
handleClick = id => {
this.setState(state => ({
...state,
settings: listItems.map(item =>
item.id === id ? { ...item, open: !item.open } : item
)
}));
};
const menuItem = () => (
<Box className={classes.menuSliderContainer} component="div">
<Avatar
className={classes.avatar}
src="#"
alt="abc"
/>
<Divider />
<List component="nav">
{listItems.map((each, index1) => (
(() => {
if (each.hidden === false) {
if (each.subMenu !== null) {
return (
<React.Fragment key={index1}>
<ListItemButton className={classes.listItem} onClick={() => this.handleClick(each.id)}>
<ListItemText primary={each.title} />
</ListItemButton>
<Divider />
<Collapse
in={listItems.find(item => item.id === each.id).open}
timeout="auto"
unmountOnExit
>
<List component="div" disablePadding style={{marginLeft: "22px"}}>
{each.subMenu.map((subData, index2) => (
(() => {
if (subData.hidden === false) {
return (
<ListItem className={classes.listItem} key={index2} button>
<ListItemText primary={subData.name} />
</ListItem>
);
}
})()
))}
</List>
</Collapse>
</React.Fragment>
);
}
else if (each.subMenu === null) {
return (
<React.Fragment key={index1}>
<ListItemButton className={classes.listItem} >
<ListItemText primary={each.title} />
</ListItemButton>
</React.Fragment>
);
}
}
})()
))}
</List>
</Box>
);
console.log(`${open} ${toggleSlider}`)
return (
<>
<Drawer classes={{paper: classes.drawer}} open={open} onClose={toggleSlider} anchor="left">
{menuItem()}
</Drawer>
</>
);
}
Solution 1:[1]
It looks as if you were destructuring your props wrongly, you wrote Sidebar({open, toggleSlider})
but on sidebar you are sending <SideBar open={open} onClose={toggleSlider} />
Sidebar({open, onClose})
should work
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Chukwuemeka Ihedoro |