I'm doing some practice with material on react but i've encountered a problem with menu.
The weird thing is that i have two IconButton components,
if I put the onClick that set the anchor element on the first IconButton, all works well.
If I put the onClick that set the anchor element on the second IconButton, the menu will never close..
why it happens? and how to solve it?
here is the code:
import React from 'react';
import AppBar from '#mui/material/AppBar';
import Toolbar from '#mui/material/Toolbar';
import Avatar from '#mui/material/Avatar';
import Menu from '#mui/material/Menu';
import MenuItem from '#mui/material/MenuItem';
import IconButton from '#mui/material/IconButton';
import MenuIcon from '#mui/icons-material/Menu';
import AccountIcon from '#mui/icons-material/AccountCircle';
function TopComp(props) {
const [anchorEl, setAnchorEl] = React.useState(null);
const isMenuOpen = Boolean(anchorEl);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
return (
<div style={{ marginBottom: '30px' }}>
<AppBar position="static" color="primary">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
//onClick={(event) => handleMenuClick(event)}
>
<MenuIcon />
</IconButton>
<div style={{ marginLeft: 'auto' }}>
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
onClick={(event) => handleMenuClick(event)}
>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={isMenuOpen}
onClose={handleMenuClose}
>
<MenuItem onClick={handleMenuClose}>Profile</MenuItem>
<MenuItem onClick={handleMenuClose}>My account</MenuItem>
<MenuItem onClick={handleMenuClose}>Logout</MenuItem>
</Menu>
<Avatar>
<AccountIcon />
</Avatar>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
export default TopComp;
Put your Menu component out of the IconButtons :-
import React from 'react';
import AppBar from '#mui/material/AppBar';
import Toolbar from '#mui/material/Toolbar';
import Avatar from '#mui/material/Avatar';
import Menu from '#mui/material/Menu';
import MenuItem from '#mui/material/MenuItem';
import IconButton from '#mui/material/IconButton';
import MenuIcon from '#mui/icons-material/Menu';
import AccountIcon from '#mui/icons-material/AccountCircle';
function TopComp(props) {
const [anchorEl, setAnchorEl] = React.useState(null);
const isMenuOpen = Boolean(anchorEl);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
return (
<div style={{ marginBottom: '30px' }}>
<AppBar position="static" color="primary">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
onClick={(event) => handleMenuClick(event)}
>
<MenuIcon />
</IconButton>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={isMenuOpen}
onClose={handleMenuClose}
>
<MenuItem onClick={handleMenuClose}>Profile</MenuItem>
<MenuItem onClick={handleMenuClose}>My account</MenuItem>
<MenuItem onClick={handleMenuClose}>Logout</MenuItem>
</Menu>
<div style={{ marginLeft: 'auto' }}>
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
onClick={(event) => handleMenuClick(event)}
>
<Avatar>
<AccountIcon />
</Avatar>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
export default TopComp;
On codesandbox.io
Related
I am trying to build a dashboard app with basic AppBar and a drawer based on this Demo
https://codesandbox.io/s/nj3u0q?file=/demo.tsx
But in this Demo, AppBar and Drawer and the Main content are all in a single page.
But I made it as separate components and did the layout like this
RootContainer.tsx
import * as React from 'react';
import { styled, useTheme } from '#mui/material/styles';
import Box from '#mui/material/Box';
import CssBaseline from '#mui/material/CssBaseline';
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '#mui/material/AppBar';
import Drawer from './Drawer';
import AppBar from './AppBar';
import Main from './MainContent';
export default function PersistentDrawerLeft() {
const [open, setOpen] = React.useState(false);
return (
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar />
<Drawer />
<Main />
</Box>
);
}
Appbar.tsx
import * as React from 'react';
import { styled, useTheme } from '#mui/material/styles';
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '#mui/material/AppBar';
import Toolbar from '#mui/material/Toolbar';
import Typography from '#mui/material/Typography';
import IconButton from '#mui/material/IconButton';
import MenuIcon from '#mui/icons-material/Menu';
const drawerWidth = 240;
interface AppBarProps extends MuiAppBarProps {
open?: boolean;
}
const AppBar = styled(MuiAppBar, {
shouldForwardProp: (prop) => prop !== 'open',
})<AppBarProps>(({ theme, open }) => ({
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
...(open && {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: `${drawerWidth}px`,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
}),
}));
export default function AppBar() {
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
return (
<AppBar position="fixed" style={{background:'#002a5e'}} open={open}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
sx={{ mr: 2, ...(open && { display: 'none' }) }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div">
Test
</Typography>
</Toolbar>
</AppBar>
);
}
But the problem is when I click the sandwich button on the appbar, it reduces its width to show the Drawer, but the drawer not at all showing.
Drawer.tsx
import * as React from "react";
import { styled, useTheme } from "#mui/material/styles";
import Drawer from "#mui/material/Drawer";
import List from "#mui/material/List";
import Divider from "#mui/material/Divider";
import IconButton from "#mui/material/IconButton";
import ChevronLeftIcon from "#mui/icons-material/ChevronLeft";
import ChevronRightIcon from "#mui/icons-material/ChevronRight";
import ListItem from "#mui/material/ListItem";
import ListItemButton from "#mui/material/ListItemButton";
import ListItemIcon from "#mui/material/ListItemIcon";
import ListItemText from "#mui/material/ListItemText";
import InboxIcon from "#mui/icons-material/MoveToInbox";
import MailIcon from "#mui/icons-material/Mail";
const drawerWidth = 240;
const DrawerHeader = styled("div")(({ theme }) => ({
display: "flex",
alignItems: "center",
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
justifyContent: "flex-end",
}));
export default function Drawer() {
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
"& .MuiDrawer-paper": {
width: drawerWidth,
boxSizing: "border-box",
},
}}
variant="persistent"
anchor="left"
open={open}
>
<DrawerHeader>
<IconButton onClick={handleDrawerClose}>
{theme.direction === "ltr" ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</DrawerHeader>
<Divider />
<List>
{["Manage Recipe", "Reports", "Settings"].map((text, index) => (
<ListItem key={text} disablePadding>
<ListItemButton>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
</Drawer>
);
}
I guess this problem is because the open constant is not getting updated into the drawer component. I am pretty new or only fews days of experience in react. Please help how can share these click event and constant in appbar to the drawer
It looks like with the separation, each component is having their own open state and handling functions, therefore the behavior is not shared.
Try pass these as props from the parent to communicate with children components.
React document about: Passing Props to a Component
There seems to be already a open state in the parent component RootContainer, so perhaps this state and handlers can be passed as props to the components, such as below example.
Over simplified example from forked demo: codesandbox
Define state and handler in the parent component, and pass these down to the children:
RootContainer.tsx
export default function PersistentDrawerLeft() {
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<Box sx={{ display: "flex" }}>
<CssBaseline />
<AppBar open={open} onDrawerOpen={handleDrawerOpen} />
<Drawer open={open} onDrawerClose={handleDrawerClose} />
<Main />
</Box>
);
}
Have each child component use the open state and handlers from the props, instead of their own, so that they share the same state:
Appbar.tsx
export default function AppBar({ open, onDrawerOpen }) {
const theme = useTheme();
return (
<AppBar position="fixed" style={{ background: "#002a5e" }} open={open}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={onDrawerOpen}
edge="start"
sx={{ mr: 2, ...(open && { display: "none" }) }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div">
Test
</Typography>
</Toolbar>
</AppBar>
);
}
Drawer.tsx
export default function Drawer({ open, onDrawerClose }) {
const theme = useTheme();
return (
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
"& .MuiDrawer-paper": {
width: drawerWidth,
boxSizing: "border-box"
}
}}
variant="persistent"
anchor="left"
open={open}
>
<DrawerHeader>
<IconButton onClick={onDrawerClose}>
{theme.direction === "ltr" ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</DrawerHeader>
<Divider />
<List>
{["Manage Recipe", "Reports", "Settings"].map((text, index) => (
<ListItem key={text} disablePadding>
<ListItemButton>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
</Drawer>
);
}
Hope this will help.
I am using material-ui-popup-state to create a material ui drop down menu
In my Navbar.js i call <HoverMenu /> component
HoverMen.js is as follows
import * as React from 'react';
import withStyles from '#material-ui/core/styles/withStyles';
import Menu from 'material-ui-popup-state/HoverMenu';
import MenuItem from '#material-ui/core/MenuItem';
import ChevronRight from '#material-ui/icons/ChevronRight';
import ClickAwayListener from '#material-ui/core/ClickAwayListener';
import { Link } from 'react-router-dom';
import PopupState, {
bindHover,
bindMenu,
bindToggle
} from 'material-ui-popup-state';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
const ParentPopupState = React.createContext(null);
const menuStyles = theme => ({
button: {
color: 'white'
}
});
const HoverMenu = () => (
<PopupState variant="popover" popupId="demoMenu">
{popupState => (
<ClickAwayListener onClickAway={popupState.close}>
<div>
<IconButton edge="start" {...bindToggle(popupState)}>
<MenuIcon />
</IconButton>
<ParentPopupState.Provider value={popupState}>
<Menu
{...bindMenu(popupState)}
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
getContentAnchorEl={null}
>
<MenuItem onClick={popupState.close} to="/" component={Link}>
Home
</MenuItem>
<MenuItem onClick={popupState.close} to="/about" component={Link}>
About
</MenuItem>
<Submenu popupId="contribute" title="Contribute">
<MenuItem
onClick={popupState.close}
to="/donate"
component={Link}
>
To Samidoun
</MenuItem>
<MenuItem onClick={popupState.close}>To Benificiary</MenuItem>
<MenuItem
onClick={popupState.close}
to="/musicians"
component={Link}
>
To Musicians
</MenuItem>
</Submenu>
<MenuItem onClick={popupState.close} to="/" component={Link}>
Volunteer
</MenuItem>
<MenuItem
onClick={popupState.close}
to="/contact"
component={Link}
>
Contact
</MenuItem>
</Menu>
</ParentPopupState.Provider>
</div>
</ClickAwayListener>
)}
</PopupState>
);
export default HoverMenu;
const submenuStyles = theme => ({
menu: {
marginTop: theme.spacing(-1)
},
title: {
flexGrow: 1
},
moreArrow: {
marginRight: theme.spacing(-1)
}
});
const Submenu = withStyles(submenuStyles)(
// Unfortunately, MUI <Menu> injects refs into its children, which causes a
// warning in some cases unless we use forwardRef here.
React.forwardRef(({ classes, title, popupId, children, ...props }, ref) => (
<ParentPopupState.Consumer>
{parentPopupState => (
<PopupState
variant="popover"
popupId={popupId}
parentPopupState={parentPopupState}
>
{popupState => (
<ParentPopupState.Provider value={popupState}>
<MenuItem
{...bindHover(popupState)}
selected={popupState.isOpen}
ref={ref}
>
<span className={classes.title}>{title}</span>
<ChevronRight className={classes.moreArrow} />
</MenuItem>
<Menu
{...bindMenu(popupState)}
classes={{ paper: classes.menu }}
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
getContentAnchorEl={null}
{...props}
>
{children}
</Menu>
</ParentPopupState.Provider>
)}
</PopupState>
)}
</ParentPopupState.Consumer>
))
);
I need to change the color of the IconButton in the HoverMenu to white (something other than the primary and secondary colors)
<IconButton edge="start" {...bindToggle(popupState)}>
<MenuIcon />
</IconButton>
But i dont know how to use className in this situation.
Thank you
I found the solution as follows.
<IconButton
edge="start"
{...bindToggle(popupState)}
style={{ color: 'white' }}
>
<MenuIcon />
</IconButton>
I would like the second grid block under the title "Other Projects of Note" to be mapped through as a 3 column grid. How can I do this without creating a new component? Material-UI controls it's columns with the grid item xs={12} sm={6} and on the 3 column grid I'd need it to read as grid item xs={12} sm={6} lg={4}.
It seems like I'd be copying and pasting the <Card /> component and renaming it to achieve this. I'd like to avoid that. Demo below:
codesandbox
Here's the code for my current Card component:
import React from 'react';
import Grid from '#material-ui/core/Grid';
import Card from '#material-ui/core/Card';
import CardActionArea from '#material-ui/core/CardActionArea';
import CardActions from '#material-ui/core/CardActions';
import { makeStyles } from '#material-ui/core/styles';
import { loadCSS } from 'fg-loadcss';
import CardContent from '#material-ui/core/CardContent';
import CardMedia from '#material-ui/core/CardMedia';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import Box from '#material-ui/core/Box';
import Icon from '#material-ui/core/Icon';
import GitHubIcon from '#material-ui/icons/GitHub';
import Tooltip from '#material-ui/core/Tooltip';
import Zoom from '#material-ui/core/Zoom';
import Link from '#material-ui/core/Link';
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: '100%',
flexGrow: 1,
},
cardGrid: {
paddingTop: theme.spacing(2),
},
media: {
height: 340,
},
button: {
margin: theme.spacing(1),
},
arrow: {
color: theme.palette.common.black,
},
tooltip: {
backgroundColor: theme.palette.common.black,
},
icons: {
'& > .fab': {
marginRight: theme.spacing(4),
},
margin: '1rem 0',
},
}));
function TwoCard(props) {
const classes = useStyles();
React.useEffect(() => {
const node = loadCSS(
'https://use.fontawesome.com/releases/v5.12.0/css/all.css',
document.querySelector('#font-awesome-css')
);
return () => {
node.parentNode.removeChild(node);
};
}, []);
return (
<>
<Grid item xs={12} sm={6}>
<Card>
<CardActionArea>
<CardMedia
className={classes.media}
image={props.card.image}
title='Contemplative Reptile'
/>
<CardContent className={classes.content}>
<Typography gutterBottom variant='h5' component='h2'>
{props.card.project}
</Typography>
<Typography variant='subtitle1' gutterBottom>
{props.card.framework}
</Typography>
<Typography gutterBottom variant='body2' component='p'>
{props.card.description}
</Typography>
<Box className={classes.icons}>
<Typography gutterBottom variant='subtitle2'>
TOOLS USED
</Typography>
<Tooltip
TransitionComponent={Zoom}
arrow
title='REACT'
aria-label='react'
>
<Icon className='fab fa-react fa-3x' color='primary' />
</Tooltip>
<Tooltip
TransitionComponent={Zoom}
arrow
title='HTML5'
aria-label='add'
>
<Icon className='fab fa-html5 fa-3x' color='primary' />
</Tooltip>
<Tooltip
TransitionComponent={Zoom}
arrow
title='CSS3'
aria-label='add'
>
<Icon className='fab fa-css3 fa-3x' color='primary' />
</Tooltip>
</Box>
</CardContent>
</CardActionArea>
<CardActions>
<Button variant='outlined' size='small' color='primary'>
<Link
href={props.card.projectUrl}
target='_blank'
rel='noopener noreferrer'
className={classes.links}
underline='none'
color='inherit'
>
View Project
</Link>
</Button>
<Button
variant='outlined'
size='small'
color='primary'
className={classes.button}
endIcon={<GitHubIcon />}
>
<Link
href={props.card.githubUrl}
target='_blank'
rel='noopener noreferrer'
underline='none'
color='inherit'
>
Code
</Link>
</Button>
</CardActions>
</Card>
</Grid>
</>
);
}
export default TwoCard;
and here's the code that uses that Card component:
import React from "react";
import Grid from "#material-ui/core/Grid";
import Card from "./Card.js";
import { Typography } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
headings: {
padding: "20px 0"
}
}));
function Projects(props) {
const classes = useStyles();
let cards = props.data.map((card, i) => {
return <Card card={card} key={i} />;
});
return (
<>
<Typography variant="h4" gutterBottom>
Featured Projects
</Typography>
<Grid container spacing={2}>
{cards}
</Grid>
<Typography variant="h4" className={classes.headings}>
Other Projects of note
</Typography>
<Grid container spacing={2}>
{cards}
</Grid>
</>
);
}
export default Projects;
You can pass a prop to your Card component to control whether it is two-column or three-column. For instance, you can pass a maxColumns prop and use it in the following manner:
<Grid item xs={12} sm={6} lg={maxColumns > 2 ? 4 : undefined}>
Then your Projects component can pass the prop (in my example, I'm defaulting maxColumns to 2, so it doesn't need to be specified in that case):
import React from "react";
import Grid from "#material-ui/core/Grid";
import Card from "./Card.js";
import { Typography } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
headings: {
padding: "20px 0"
}
}));
function Projects(props) {
const classes = useStyles();
let twoColumnCards = props.data.map((card, i) => {
return <Card card={card} key={i} />;
});
let threeColumnCards = props.data.map((card, i) => {
return <Card maxColumns={3} card={card} key={i} />;
});
return (
<>
<Typography variant="h4" gutterBottom>
Featured Projects
</Typography>
<Grid container spacing={2}>
{twoColumnCards}
</Grid>
<Typography variant="h4" className={classes.headings}>
Other Projects of note
</Typography>
<Grid container spacing={2}>
{threeColumnCards}
</Grid>
</>
);
}
export default Projects;
I'm using react Material UI in an application, but found some missing logic with my react code.
My complete App.js source file is written below
import React from 'react';
import { fade,makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
import Icon from '#material-ui/core/Icon';
// import { browserHistory, Router, Route } from 'react-router';
import { BrowserRouter as Router, Route,Redirect } from "react-router-dom";
import './App.css';
/* AppBar*/
//import { fade, makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import IconButton from '#material-ui/core/IconButton';
import Typography from '#material-ui/core/Typography';
import InputBase from '#material-ui/core/InputBase';
import Badge from '#material-ui/core/Badge';
import MenuItem from '#material-ui/core/MenuItem';
import Menu from '#material-ui/core/Menu';
import MenuIcon from '#material-ui/icons/Menu';
import SearchIcon from '#material-ui/icons/Search';
import AccountCircle from '#material-ui/icons/AccountCircle';
import MailIcon from '#material-ui/icons/Mail';
import NotificationsIcon from '#material-ui/icons/Notifications';
import MoreIcon from '#material-ui/icons/MoreVert';
/*App bar */
import ImgMediaCard from './ImgMediaCard';
import GridList from '#material-ui/core/GridList';
import GridListTile from '#material-ui/core/GridListTile';
import DemoCarousel from './MCarousel'
import Register from './Register'
var gridListStyle = {
marginLeft: "40px"
};
const useStyles = makeStyles(theme => ({
grow: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
},
},
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginRight: theme.spacing(2),
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(3),
width: 'auto',
},
},
searchIcon: {
width: theme.spacing(7),
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
inputRoot: {
color: 'inherit',
},
inputInput: {
padding: theme.spacing(1, 1, 1, 7),
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('md')]: {
width: 200,
},
},
sectionDesktop: {
display: 'none',
[theme.breakpoints.up('md')]: {
display: 'flex',
},
},
sectionMobile: {
display: 'flex',
[theme.breakpoints.up('md')]: {
display: 'none',
},
}
}));
/*end App bar work*/
const useGridStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
},
paper: {
// padding: theme.spacing(2),
// textAlign: 'center',
// color: theme.palette.text.secondary,
},
}));
function App() {
const Gridclasses = useGridStyles();
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState(null);
const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null);
const isMenuOpen = Boolean(anchorEl);
const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);
const handleProfileMenuOpen = event => {
setAnchorEl(event.currentTarget);
};
const handleMobileMenuClose = () => {
setMobileMoreAnchorEl(null);
};
const handleMenuClose = () => {
setAnchorEl(null);
handleMobileMenuClose();
};
const handleMobileMenuOpen = event => {
setMobileMoreAnchorEl(event.currentTarget);
};
const onRegisterClick = () => {
debugger;
//if(userFound){
<Router>
<Route exact path="/Register" component={Register} />
return <Redirect to="/Register" />
</Router>
// }
};
// const addRoutes = () =>{
// };
let nums = Array.from(Array(40).keys());
const menuId = 'primary-search-account-menu';
const renderMenu = (
<Menu
anchorEl={anchorEl}
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
id={menuId}
keepMounted
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
open={isMenuOpen}
onClose={handleMenuClose}
>
<MenuItem onClick={handleMenuClose}>Profile</MenuItem>
<MenuItem onClick={handleMenuClose}>My account</MenuItem>
</Menu>
);
const mobileMenuId = 'primary-search-account-menu-mobile';
const renderMobileMenu = (
<Menu
anchorEl={mobileMoreAnchorEl}
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
id={mobileMenuId}
keepMounted
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
open={isMobileMenuOpen}
onClose={handleMobileMenuClose}
>
<MenuItem>
<Icon className="fa fa-plus-circle" />
</MenuItem>
<MenuItem>
<IconButton aria-label="show 4 new mails" color="inherit">
<Badge badgeContent={4} color="secondary">
<MailIcon />
</Badge>
</IconButton>
<p>Messages</p>
</MenuItem>
<MenuItem>
<IconButton aria-label="show 11 new notifications" color="inherit">
<Badge badgeContent={11} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
<p>Notifications</p>
</MenuItem>
<MenuItem onClick={handleProfileMenuOpen}>
<IconButton
aria-label="account of current user"
aria-controls="primary-search-account-menu"
aria-haspopup="true"
color="inherit"
>
<AccountCircle />
</IconButton>
<p>Profile</p>
</MenuItem>
</Menu>
);
return (
<div className={Gridclasses.root}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Paper className={Gridclasses.paper}>
<div className={classes.grow}>
<AppBar position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="open drawer"
>
<MenuIcon />
</IconButton>
<Typography className={classes.title} variant="h6" noWrap>
Shopping Center
</Typography>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ 'aria-label': 'search' }}
/>
</div>
<div className={classes.grow} />
<div className={classes.sectionDesktop}>
<IconButton aria-label="" color="inherit" onClick={onRegisterClick}> Sign Up
</IconButton>
<IconButton aria-label="show 4 new mails" color="inherit">
<Badge badgeContent={4} color="secondary">
<MailIcon />
</Badge>
</IconButton>
<IconButton aria-label="show 17 new notifications" color="inherit">
<Badge badgeContent={17} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
<IconButton
edge="end"
aria-label="account of current user"
aria-controls={menuId}
aria-haspopup="true"
onClick={handleProfileMenuOpen}
color="inherit"
>
<AccountCircle />
</IconButton>
</div>
<div className={classes.sectionMobile}>
<IconButton
aria-label="show more"
aria-controls={mobileMenuId}
aria-haspopup="true"
onClick={handleMobileMenuOpen}
color="inherit"
>
<MoreIcon />
</IconButton>
</div>
</Toolbar>
</AppBar>
{renderMobileMenu}
{renderMenu}
</div>
</Paper>
</Grid>
<GridList cols={3} style={gridListStyle} cellHeight={"auto"}>
{nums.map(n => {
return (
<GridListTile key={n}>
<ImgMediaCard key={n} num={n} />
</GridListTile>
);
})}
</GridList>
<Grid item xs={6} sm={3}>
<Paper className={Gridclasses.paper}> <DemoCarousel />
</Paper>
</Grid>
</Grid>
</div>
);
}
export default App;
and following function don't take me into the second component. I don't know why.
const onRegisterClick = () => {
debugger;
//if(userFound){
<Router>
<Route exact path="/Register" component={Register} />
return <Redirect to="/Register" />
</Router>
// }
};
As I'm a newbie with react. What should I do in my code?
I've grabbed the example code for a menus and cards from here: https://material-ui.com
Application built with
{
"react": "16.13.0",
"react-dom": "^16.13.0",
"react-redux": "^7.2.0",
"react-router-dom": "^5.1.2",
"redux": "^4.0.4"
"#material-ui/core": "^4.9.5"
}
The Signup button don't allow me to navigate to Register react component.
Output: Sign Up button should allow me to redirect.
I tried to follow guides and looked up example implementations but could not solve the issue.
Only the render and functions called directly from render function are supposed to return JSX because these are the functions that render UI.
When you consider something like onRegisterClick function, this function is called in response to a button being clicked. Here you should be adding the imperative code to redirect the user to /redirect page. But the Route for redirect should be setup before this function is ever called so React Router knows which component to render.
Your whole app (generally) requires a single Router component and your whole App is wrapped into it, in you case consider something like:
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(<Router>
<Route path="/Register" component={Register} />
<Route exact path="/" component={App />
</Router>, document.getElementById("root") />
After this, you can navigate with:
function App({ history }) {
const onRegisterClick = () => {
history.push('/register');
}
}
There is a lot of assumptions here and I do think you need to check out React Router docs and understand the routing a little better before you can get started.
Making a Drawer in React.Js with Material-UI.
When I switch to the mobile view, the Drawer content automatically shifts to the right side with a lot of margin.
It works fine the in desktop view.
I am not able to find the error in this code.
Could anyone guide me how can I solve this issue?
The code for the drawer:
import React from 'react';
[import PropTypes from 'prop-types';
import AppBar from '#material-ui/core/AppBar';
import CssBaseline from '#material-ui/core/CssBaseline';
import Divider from '#material-ui/core/Divider';
import Drawer from '#material-ui/core/Drawer';
import Hidden from '#material-ui/core/Hidden';
import IconButton from '#material-ui/core/IconButton';
import List from '#material-ui/core/List';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import { makeStyles, useTheme } from '#material-ui/core/styles';
import { ListItem } from '#material-ui/core';
import { Data } from './data';
const drawerWidth = 240;
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
},
drawer: {
\[theme.breakpoints.up('sm')\]: {
width: drawerWidth,
flexShrink: 0,
},
},
appBar: {
marginLeft: drawerWidth,
\[theme.breakpoints.up('sm')\]: {
width: `calc(100% - ${drawerWidth}px)`,
},
},
menuButton: {
marginRight: theme.spacing(2),
\[theme.breakpoints.up('sm')\]: {
display: 'none',
},
},
toolbar: theme.mixins.toolbar,
drawerPaper: {
width: drawerWidth,
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
},
}));
function ResponsiveDrawer(props) {
const { container } = props;
const classes = useStyles();
const theme = useTheme();
const \[mobileOpen, setMobileOpen\] = React.useState(false);
var \[index, changeindex\] = React.useState(1);
function handleDrawerToggle() {
setMobileOpen(!mobileOpen);
}
const drawer = (
<div>
<div className={classes.toolbar} />
<Divider></Divider>
<List>
<ListItem button primary full large onClick = {()=>changeindex(index = 1)} > <Typography variant="h6" noWrap>
Test 1
</Typography></ListItem>
<ListItem button primary full large onClick={() => changeindex(index = 2)} >
<Typography variant="h6" noWrap>
Test2
</Typography>
</ListItem>
<ListItem button primary full large onClick={() => changeindex(index = 3)} >
<Typography variant="h6" noWrap>
Test3
</Typography>
</ListItem>
</List>
</div>
);
console.log(props);
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
className={classes.menuButton}
>
<i class="material-icons">view_headline</i>
</IconButton>
<Typography variant="h6" noWrap>
Responsive drawer
</Typography>
</Toolbar>
</AppBar>
<nav className={classes.drawer} aria-label="mailbox folders">
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
<Hidden smUp implementation="css">
<Drawer
container={container}
variant="temporary"
anchor={theme.direction === 'rtl' ? 'right' : 'left'}
open={mobileOpen}
onClose={handleDrawerToggle}
classes={{
paper: classes.drawerPaper,
}}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
{drawer}
</Drawer>
</Hidden>
<Hidden xsDown implementation="css">
<Drawer
classes={{
paper: classes.drawerPaper,
}}
variant="permanent"
open
>
{drawer}
</Drawer>
</Hidden>
</nav>
<main className={classes.content}>
<div className={classes.toolbar} />
{/* {console.log(index)} */}
<Data index={index} ></Data>
</main>
</div>
);
}
ResponsiveDrawer.propTypes = {
/**
* Injected by the documentation to work in an iframe.
* You won't need it on your project.
*/
container: PropTypes.instanceOf(typeof Element === 'undefined' ? Object : Element),
};
export default ResponsiveDrawer;][1]
Example image