I make a button to control the menu but I click the button and then nothing happen.There aren't run out any error msg.
const [display, changeDisplay] = useState('none')
const [Icon, setIcon] = useState(<HamburgerIcon />)
function Close() {
return (
<Box as='button' onClick={() => changeDisplay('none')}><CloseIcon /></Box>
)
}
<Box
as="button"
aria-label="Open Menu"
position="relative"
onClick={() => { changeDisplay('flex'); setIcon(<Close />) }}
display={{ base: 'inline-block', md: 'none' }}
margin={2}
>
{Icon}
</Box>
replace the following code:
onClick={() => { changeDisplay('flex'); setIcon(<Close />) }}
with:
onClick={() => {changeDisplay('flex'); setIcon(Close())}}
Related
According to the documentation, I can override the style of the selected class by passing a new class under .MuiSelected. something like below:
const useStyles = makeStyles(() => ({
selectedLink: {
"&.Mui-selected": {
backgroundColor: "red",
},
},
}));
Then, I use it:
const MainDrawerMenu: React.FC = () => {
const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);
const [selectedIndex, setSelectedIndex] = React.useState(0);
const classes = useStyles();
// Responsive swipe on mobile
const iOS =
typeof navigator !== "undefined" &&
/iPad|iPhone|iPod/.test(navigator.userAgent);
const handleSelected = (
e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
selectedIndex: number
) => {
setSelectedIndex(selectedIndex);
};
return (
<React.Fragment>
<SwipeableDrawer
classes={{ paper: classes.drawerMenuHolder }}
disableBackdropTransition={!iOS}
disableDiscovery={iOS}
open={isDrawerOpen}
onClose={() => {
setIsDrawerOpen(false);
}}
onOpen={() => {
setIsDrawerOpen(true);
}}>
<List disablePadding>
<ListItemButton
component={Link}
classes={{ selected: classes.selectedLink }}
to='/'
onClick={(event) => {
setIsDrawerOpen(false);
handleSelected(event, 0);
}}
selected={selectedIndex === 0}>
<ListItemText disableTypography className={classes.drawerItem}>
Home
</ListItemText>
</ListItemButton>
</List>
</SwipeableDrawer>
<IconButton
className={classes.iconMenuBtn}
onClick={() => {
setIsDrawerOpen(!isDrawerOpen);
}}>
<MenuIcon fontSize='large' className={classes.menuIcon} />
</IconButton>
</React.Fragment>
);
};
Yet, it doesn't work. I can see it in the dev tools, but for some reason it gets overridden by another class. See screenshot. I have tried also creating a new class with the css naming convention but no luck...
Solution below:
<ListItemButton sx={{
'&.Mui-selected': {
backgroundColor: 'rgba(220, 0, 50, 0.1)'
}
}} selected={0}>
<ListItemText primary={'label in item selected'} />
</ListItemButton>
I followed the documentation to create a dropdown menu using Material UI. However, none of the docs have a good example for handling multiple dropdowns in the same menu.
I got it mostly working - however, when I open a dropdown, they ALL open. I'm assuming this is because open = Boolean(anchorEl) opens the menu whenever an anchorEl is set. So how can I adjust this so it only opens the specific menu that is clicked?
const NavBarMainMenu = () => {
const [anchorEl, setAnchorEl] = useState(null)
const open = Boolean(anchorEl)
const handleClick = event => {
setAnchorEl(event.currentTarget)
}
const handleClose = () => {
setAnchorEl(null)
}
return (
<>
<Box sx={{ flexGrow: 1, display: { xs: "none", lg: "flex" } }}>
{pages.map(page => {
return (
<>
<Button
key={page.title}
id={page.title + "-button"}
onClick={handleClick}
aria-controls={open ? page.title : undefined}
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
>
{page.title}
</Button>
<Menu
anchorEl={anchorEl}
id={page.title}
open={open}
onClose={handleClose}
onClick={handleClose}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
>
{page.children.map(child => {
return <MenuItem key={child.title}>{child.title}</MenuItem>
})}
</Menu>
</>
)
})}
</Box>
</>
)
}
You can try something like this:
const NavBarMainMenu = () => {
const [anchorEls, setAnchorEls] = useState({}) // <-- Here use a object
const isOpen = (id) => Boolean(anchorEls[id]) // <-- Here you need a function to get if open is true
const handleClick = (event, id) => {
setAnchorEsl({ ...anchorEls, [id]: event.currentTarget }) // <-- Here you set anchor value using an id
}
const handleClose = (id) => {
setAnchorEls({ ...anchorEls, [id]: null }) // <-- Here you delete anchor value by ID
}
return (
<>
<Box sx={{ flexGrow: 1, display: { xs: "none", lg: "flex" } }}>
{pages.map(page => {
return (
<>
<Button
key={page.title}
id={page.title + "-button"}
onClick={(event) => handleClick(event, page.title)}
aria-controls={isOpen(page.title) ? page.title : undefined}
aria-haspopup="true"
aria-expanded={isOpen(page.title) ? "true" : undefined}
>
{page.title}
</Button>
<Menu
anchorEl={anchorEls[page.title]}
id={page.title}
open={isOpen(page.title)}
onClose={() => handleClose(page.title)}
onClick={() => handleClose(page.title)}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
>
{page.children.map(child => {
return <MenuItem key={child.title}>{child.title}</MenuItem>
})}
</Menu>
</>
)
})}
</Box>
</>
)
}
I have imported a schedular component from devexpress and have modified the appointments in this with the constant MyAppointment. Now i want to be able to delete and modify apointment data with a dialog when clicking on these. Therefore i added an onClick method to the MyAppointment const and tried to return the dialog however nothing happens when pressing the appointments.
const MyAppointment = ({ children, style, ...restProps }) => {
return (
<Appointments.Appointment
{...restProps}
style={{
...style,
backgroundColor: "#a02d37",
borderRadius: "8px",
}}
onClick={()=>{
return (
<SimpleDialogDemo />
)
}}
>
{children}
</Appointments.Appointment>
);
}
const emails = ['username#gmail.com', 'user02#gmail.com'];
function SimpleDialog(props) {
const { onClose, selectedValue, open } = props;
const handleClose = () => {
onClose(selectedValue);
};
const handleListItemClick = (value) => {
onClose(value);
};
return (
<Dialog onClose={handleClose} open={open}>
<DialogTitle>Set backup account</DialogTitle>
<List sx={{ pt: 0 }}>
{emails.map((email) => (
<ListItem button onClick={() => handleListItemClick(email)} key={email}>
<ListItemAvatar>
<Avatar sx={{ bgcolor: blue[100], color: blue[600] }}>
<PersonIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary={email} />
</ListItem>
))}
<ListItem autoFocus button onClick={() => handleListItemClick('addAccount')}>
<ListItemAvatar>
<Avatar>
<AddIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary="Add account" />
</ListItem>
</List>
</Dialog>
);
}
SimpleDialog.propTypes = {
onClose: PropTypes.func.isRequired,
open: PropTypes.bool.isRequired,
selectedValue: PropTypes.string.isRequired,
};
export default function SimpleDialogDemo() {
const [open, setOpen] = React.useState(true);
const [selectedValue, setSelectedValue] = React.useState(emails[1]);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = (value) => {
setOpen(false);
setSelectedValue(value);
};
handleClickOpen();
return (
<div>
<SimpleDialog
selectedValue={selectedValue}
open={open}
onClose={handleClose}
/>
</div>
);
}
onClick={()=>{
return (
<SimpleDialogDemo />
)
}}
isn't actually doing anything. All you're doing is returning a component in an event handler that doesn't do anything with that return value. The onClick event handler is react-agnostic.
If you want to display a component when something is clicked, you'll need to use local state variables to show/hide it based on a click action like below:
const MyAppointment = ({ children, style, ...restProps }) => {
const [showDialog, setShowDialog] = useState(false);
return (
<Appointments.Appointment
{...restProps}
style={{
...style,
backgroundColor: "#a02d37",
borderRadius: "8px",
}}
onClick={()=> setShowDialog(true)}
>
{children}
{showDialog && <SimpleDialogDemo onClose=(() => setShowDialog(false))/>}
</Appointments.Appointment>
);
}
Note the onClose prop I added to your SimpleDialog component so that you have a way of setting the showDialog state back to hidden (you will need to add this propr if you use it).
I have an array of data and map it into Popover component. These components have MenuItem which contains some data. But they render only the last data, instead of the different data that exists. Example:
Wrong data, should be to 59 as shown below. The textfield and popover contain the same MenuItem components, only thing different is the popovers.
Code:
const [anchorEl, setAnchorEl] = React.useState(null);
const handlePopoverClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handlePopoverClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;
// New section
<Fab
className={classes.fabStyle}
size="small"
variant="outlined"
onClick={handlePopoverClick}
>
<ExpandMoreIcon />
</Fab>
<Popover
id={id}
open={open}
className={classes.popoverContainer}
anchorEl={anchorEl}
onClose={handlePopoverClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
}}
PaperProps={{ elevation: 1 }}
>
{action.children.map((child) => {
if (child.type === "link") {
console.log(child.to);
return (
<MenuItem>
<Link
style={{
textDecoration: "none",
color:
themes.default.palette
.text.primary,
}}
to={child.to}
>
{child.label}
{child.to}
</Link>
</MenuItem>
);
} else if (
child.type === "dialog"
) {
return (
<MenuItem
onClick={() =>
child.handleOpenDialog(row)
}
>
{child.label}
</MenuItem>
);
}
})}
</Popover>
I am new to react and working on a react video player. I'm having issue implementing the comment section.
This is my videoplayer component itself.
export default function VidPlayer() {
// useStates
const [state, setState] = useState({
playing: true,
});
const [comments, setComments] = useState([]);
const [comment, setComment] = useState("");
const { playing } = state;
const playerRef = useRef(null);
// declaring functions for video player buttons
const handlePlayPause = () => {
setState({ ...state, playing: !state.playing });
};
const handleRewind = () => {
playerRef.current.seekTo(playerRef.current.getCurrentTime() - 5);
};
const handleFoward = () => {
playerRef.current.seekTo(playerRef.current.getCurrentTime() + 5);
};
const handleStop = () => {
playerRef.current.seekTo(0);
setState({ playing: !state.playing });
};
// declaring functions for comment section
const addComments = () => {
if (comment) {
setComments({...comments, comment});
setComment("");
console.log("Hello", comments);
}
};
const handleComment = (e) => {
setComment(e.target.value);
};
return (
<div>
<AppBar style={{ background: "#e6880e" }} position="static">
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
Favour's Video Player
</Typography>
</Toolbar>
</AppBar>
{/* container for the videoplayer, buttons and comment section */}
<div className="container">
<>
{/* videoplayer */}
<div className="reactPlayer one">
<ReactPlayer
ref={playerRef}
url="https://www.youtube.com/watch?v=1_ATK0BLc8U&t=3s"
playing={playing}
controls
/>
</div>
{/* buttons */}
<div className="btn-stack two">
<Stack spacing={2} direction="row">
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handlePlayPause}
>
Play
</Button>
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handleRewind}
>
Rewind{" "}
</Button>
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handleFoward}
>
Forward{" "}
</Button>
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handleStop}
>
Stop
</Button>
</Stack>
</div>
{/* comment section */}
<div className="comment three">
<Comment userComs={comments} />
<TextField
placeholder="add comment"
size="small"
variant="outlined"
onChange={handleComment}
value={comment}
/>
<Button
style={{ background: "#e6880e", marginLeft: '1em' }}
onClick={addComments}
variant="contained"
size="small"
>
Send
</Button>
</div>
</>
</div>
</div>
);
}
It takes in this comments component towards the end.
export default function commentList(props) {
console.log("Hello brian", props.userComs);
const { userComs } = props;
if (Object.keys(userComs).length > 0) {
console.log(userComs);
// userComs.forEach((element) => {
// console.log("Im in", userComs);
Object.values(userComs).forEach(val => {
// console.log("Im in", userComs);
// console.log(val);
return (
<div>
<List
sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper" }}
>
<ListItem alignItems="flex-start">
<ListItemAvatar>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
</ListItemAvatar>
<ListItemText
secondary={
<React.Fragment>
<Typography
sx={{ display: "inline" }}
component="span"
variant="body2"
color="text.primary"
>
Ali Connors
</Typography>
{val}
</React.Fragment>
}
/>
</ListItem>
<Divider variant="inset" component="li" />
</List>
</div>
);
});
} else {
return <div></div>;
}
}
This is the Front-End enter image description here
Unfortunately, when I enter a comment and click send, the screen goes blank and console throws a "nothing was returned from render" error. Can someone help me check what is wrong and how I can fix this please?
As the error says, the component isn't returning anything.
Object.values(userComs).forEach(val => {
should be
return Object.values(userComs).map(val => {
because forEach doesn't return anything and the JSX returned in each iteration will not be used anywhere, but map returns a new array that React can use.
BTW make sure to give a key prop to each div that is returned from the callback.
<div key={val}> // assuming `val` is unique