I'm trying to learn react and fairly new to the framework. I am trying to create a simple navbar component wih material-ui that is responsive (will show all links on medium devices and up, and open a side drawer on small devices). I have most of it setup to my liking, however, the issue I am currently having, is getting and setting the active link according to the page I am on.
It seems to works correctly on the medium devices and up, but when transitioning to a smaller device, the link is not updated correctly, as it will keep the active link from the medium screen set, while updating the side drawer active link.
Navbar.js
const Navbar = () => {
const classes = useStyles();
const pathname = window.location.pathname;
const path = pathname === '' ? '' : pathname.substr(1);
const [selectedItem, setSelectedItem] = useState(path);
const handleItemClick = (event, selected) => {
setSelectedItem(selected);
console.log(selectedItem);
};
return (
<>
<HideNavOnScroll>
<AppBar position="fixed">
<Toolbar component="nav" className={classes.navbar}>
<Container maxWidth="lg" className={classes.navbarDisplayFlex}>
<List>
<ListItem
button
component={RouterLink}
to="/"
selected={selectedItem === ''}
onClick={event => handleItemClick(event, '')}
>
<ListItemText className={classes.item} primary="Home" />
</ListItem>
</List>
<Hidden smDown>
<List
component="nav"
aria-labelledby="main navigation"
className={classes.navListDisplayFlex}
>
<ListItem
button
component={RouterLink}
to="/account/login"
selected={selectedItem === 'account/login'}
onClick={event => handleItemClick(event, 'account/login')}
>
<ListItemText className={classes.item} primary="Login" />
</ListItem>
<ListItem
button
component={RouterLink}
to="/account/register"
selected={selectedItem === 'account/register'}
onClick={event => handleItemClick(event, 'account/register')}
>
<ListItemText className={classes.item} primary="Register" />
</ListItem>
</List>
</Hidden>
<Hidden mdUp>
<SideDrawer />
</Hidden>
</Container>
</Toolbar>
</AppBar>
</HideNavOnScroll>
<Toolbar id="scroll-to-top-anchor" />
<ScrollToTop>
<Fab aria-label="Scroll back to top">
<NavigationIcon />
</Fab>
</ScrollToTop>
</>
)
}
SideDrawer.js
const SideDrawer = () => {
const classes = useStyles();
const [state, setState] = useState({ right: false });
const pathname = window.location.pathname;
const path = pathname === "" ? "" : pathname.substr(1);
const [selectedItem, setSelectedItem] = useState(path);
const handleItemClick = (event, selected) => {
setSelectedItem(selected);
console.log(selectedItem);
};
const toggleDrawer = (anchor, open) => (event) => {
if (
event &&
event.type === "keydown" &&
(event.key === "Tab" || event.key === "Shift")
) {
return;
}
setState({ ...state, [anchor]: open });
};
const drawerList = (anchor) => (
<div
className={classes.list}
role="presentation"
onClick={toggleDrawer(anchor, false)}
onKeyDown={toggleDrawer(anchor, false)}
>
<List component="nav">
<ListItem
button
component={RouterLink}
to="/account/login"
selected={selectedItem === "account/login"}
onClick={(event) => handleItemClick(event, "account/login")}
>
<ListItemText className={classes.item} primary="Login" />
</ListItem>
<ListItem
button
component={RouterLink}
to="/account/login"
selected={selectedItem === "account/register"}
onClick={(event) => handleItemClick(event, "account/register")}
>
<ListItemText className={classes.item} primary="Register" />
</ListItem>
</List>
</div>
);
return (
<React.Fragment>
<IconButton
edge="start"
aria-label="Menu"
onClick={toggleDrawer("right", true)}
>
<Menu fontSize="large" style={{ color: "white" }} />
</IconButton>
<Drawer
anchor="right"
open={state.right}
onClose={toggleDrawer("right", false)}
>
{drawerList("right")}
</Drawer>
</React.Fragment>
);
};
Code Sandbox - https://codesandbox.io/s/async-water-yx90j
I came across this question on SO: Is it possible to share states between components using the useState() hook in React?, which suggests that I need to lift the state up to a common ancestor component, but I don't quite understand how to apply this in my situation.