What I want:
I want to open (expand) the submenu of a specific menu when I change/update the defaultOpenKeys value.
What I've tried:
const [submenu, setSubmenu] = useState([]);
useEffect(() => {
setSubmenu(["sub1"]);
}, []);
...
<Menu style={{ width: 256 }} defaultSelectedKeys={["4"]} defaultOpenKeys={submenu} mode="inline">
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
<SubMenu key="sub1" title="Submenu">
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</SubMenu>
</Menu>;
In here, The submenu is an empty array at first, but whenever the page loads, useEffect does update the value of submenu and set to the ["sub1"]. What I believe is, whenever the state values do change, the page should re-render, so <Menu defaultOpenKeys={['sub1']} ...> should update like this, right?
But in here, if I pass <Menu defaultOpenKeys=['sub1'] ... > at first then this works as I expected, but If I pass the defaultOpenKeys value from the state, then this does not work as I expected (if the initial value of state is ['sub1'] then it also works fine).
Here is the code sandbox, where I've included both working and not working demo.
CODESANDBOX
Here is the screenshot:
UPDATED:
After #HDM91 answer,
I've tried with another prop provided by antd, which is openKeys and it does open the submenu at first, but was unable to close it, or even it does block other submenus from opening/closing.
<Menu
style={{ width: 256 }}
defaultSelectedKeys={["4"]}
openKeys={submenu} // blocks other submenu by closing and opening
mode="inline"
>
I've just tried with openKeys and and handle onOpenChange to set new openkeys into submenu state it's fine:
const [submenu, setSubmenu] = useState([]);
useEffect(() => {
setSubmenu(["sub1"]);
}, []);
return (
<Menu
style={{ width: 256 }}
defaultSelectedKeys={["4"]}
defaultOpenKeys={submenu}
openKeys={submenu}
onOpenChange={(openKeys) => {
setSubmenu(openKeys);
}}
mode="inline"
>
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
<SubMenu key="sub1" title="Submenu">
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</SubMenu>
</Menu>
);
Related
I am relatively new to react and not sure why isOpen is not working as expected.
Please see the code below for the example that I am working with
I have a menu icon that is using isOpen to open navlinks:
const { isOpen, onOpen, onClose } = useDisclosure();
<IconButton variant={"unstyled"} bgColor={"white"} color={"black"} size={"s"} icon={isOpen ? <Hamburger size={"24"} /> : <Hamburger size={"24"} />} aria-label={"Open Menu"} display={{ md: "none" }} onClick={isOpen ? onClose : onOpen} />
{isOpen ? (
<Box color={"#b8860b"} pb={4} display={{ md: "none" }}>
<Stack as={"nav"} spacing={5}>
{Links.map(link => (
<Link key={link.name} href={link.route}>
<Flex paddingBottom="40px" h="40px" borderBottom="1px" borderColor="black" justifyContent={'left'}>
<Flex paddingLeft={"10px"} paddingTop={"3%"}> {link.icon}</Flex>
<Text p={2} color={"black"} >
{link.name}
</Text>
</Flex>
</Link>
))}
</Stack>
</Box>
) : null}
When I try using a custom isOpen to open a drawer component, i just cant get it to work..
What am I doing wrong?:
const { isOpenMenu, onOpenMenu, onCloseMenu } = useDisclosure()
<Button
bgColor={"white"}
onClick={isOpenMenu}
>
<BsCart4 size={"26px"} color={"black"} />
{cartItemCount > 0 && <Badge ml='1' fontSize='0.9em' colorScheme='green'>{cartItemCount}</Badge>}
</Button>
<Drawer
isOpen={isOpenMenu}
placement='right'
onClose={onCloseMenu}
finalFocusRef={btnRef}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Create your account</DrawerHeader>
<DrawerBody>
<Input placeholder='Type here...' />
</DrawerBody>
<DrawerFooter>
<Button variant='outline' mr={3} onClick={onCloseMenu}>
Cancel
</Button>
<Button colorScheme='blue'>Save</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
```
When I use isOpen for the drawer it works fine so I thought having another isOpen but custom would open the drawer but its not working as expected.
Can someone help understand why my thinking isnt right based on how to use isOpen correctly?
It seems like only isOpen works when I switch it from using the menu bar and drawer
First of all, if you want to use custom names to the useDisclosure states, you have to set them like this:
const { isOpen: isOpenMenu, onOpen: onOpenMenu, onClose: onCloseMenu } = useDisclosure()
Also, the onClose prop of the drawer component is just a event handler, dont put your onCloseMenu function ther, just call it when you want to close the drawer, as you made on the cancel button, example:
<Button onClick={onCloseMenu} ... />
So the problem I am having is that I have a custom rendered column inside which there is a menu button clicking on it open a menu like this:
Now look at below code:
columns={[
{
title: 'Actions',
field: 'tableData.id',
render: rowData => {
return (
<div>
<IconButton aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
<MenuIcon />
</IconButton>
<Menu
className={classes.menu}
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem className={classes.sendMail} onClick={()=>
{console.log(rowData)}}>
<ListItemIcon className={classes.icon}>
<SendIcon fontSize="default" />
</ListItemIcon>
Send Assessment Email
</MenuItem>
</Menu>
</div>
)
},
},
The values coming in from the rows i.e rowData is fine on the first onClick of IconButton component but the second onClick of MenuItem shows only the last rowData value no matter which row i select.
Any help would be appreciated. Thank you.
EDIT: I have deployed a quick fix by setting the selected row on Menubutton inside useState and then using that value for the other actions but i wanna know if that is natively or shall i say possible on default rather then the approach i took . i tried stopping event propagation but in vain.
Thanks for asking this questions and seeing that I'm not completely alone...
I am not sure if this could serve as a solution or as a work around, but it works for me.
On the button being used to open the menu, I use the onClick event to set the selected menu row which I want to use, and save it
to the component state.
const [slcRow, setSlcRow] = React.useState(null);
const handleClick = (event, row) => {
setAnchorEl(event.currentTarget);
setSlcRow(row);
};
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={(event ) => {handleClick(event, row) }}
>
Open Menu
</Button>
In the MenuItem onClick event I check the state to retrieve that row and do the work needed...
const handleEditOpen = (event) => {
let row = slcRow;
loadEditData(row.clientId);
setEdit(true);
setAnchorEl(null);
};
<Menu id="long-menu" anchorEl={anchorEl} keepMounted open={open} onClose={handleClose1}>
<MenuItem onClick={(event) => { handleEditOpen(event) }}>Edit </MenuItem>
</Menu
The following question is regarding React and Material-UI:
I am trying to use the <Collapse> transition component when displaying my <Menu> onMouseEnter. However, there seems to be an issue in the Material-UI library when it comes to the way the <Collapse> component and the <Popper> / <Popover> component. The issue is currently open and can be seen here.
Has anyone found a good workaround for this? Basically, I am just hoping to have a subnav Menu appear when you hover over a link with this specific transition.
I have tried using the <Grow> component and the transition works just fine, but we specifically are trying to use the <Collapse> transition.
export const NavBarItem = ({ navItem }) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
function handleToggle() {
setOpen(prevOpen => !prevOpen);
}
function handleClose(event) {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
}
return (
<React.Fragment>
<Link className={classes.link} href={BASE_HOMEPAGE + navItem.path}>
<Typography
className={classes.title}
ref={anchorRef}
aria-controls="menu-list-grow"
aria-haspopup="true"
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
>
{navItem.title}
</Typography>
</Link>
<Popper
open={open}
anchorEl={anchorRef.current}
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
transition
disablePortal
placement="bottom-start"
>
<Collapse in={open}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={handleClose}>
<MenuList className={classes.paperMenu}>
{navItem.menuItems.map(item => (
<Link
className={classes.link}
href={
item.external ? item.path : BASE_HOMEPAGE + item.path
}
>
<MenuItem
className={classes.paperMenuItem}
onClick={handleClose}
>
{item.text}
</MenuItem>
</Link>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Collapse>
</Popper>
</React.Fragment>
);
};
The code shown above is for a specific NavItem in a NavComponent. It is essentially just a dropdown component to show a subnav when you hover over a specific link.
Thank you for your help and please let me know if you need anymore additional information.
You can try to use the TransitionProps given by the Popper when using the transition props, as shown in the documentation
<Popper id={id} open={open} anchorEl={anchorEl} transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<div className={classes.paper}>The content of the Popper.</div>
</Fade>
)}
</Popper>
For smoother UI you can also use the keepMounted property in Popper:
<Popper id={id} open={open} anchorEl={anchorEl} transition keepMounted>
I am new to the world of react and javascript.
I encounter quite a mistake with the Ant Design code for the collapsed inline menu.
I tried several solutions found on the forum but without success.
And I do not quite understand the notion of one of the errors that is "Must Use destructuring state assignment"
I stick you my code and the errors that are indicated to me.
for the error "Missing Parentheses around multilines JSX" I have already tried the mettres but I have another error that appears.
when I click on the button nothing happens
I hope you can help me.
thank you in advance
import React, { Component } from 'react';
import { Menu, Icon, Button } from 'antd';
const { SubMenu } = Menu;
class RightVerticalMenu extends Component {
state = {
collapsed: false,
};
toggleCollapsed = () => {
this.setState({
collapsed: !this.state.collapsed,
});
};
render() {
const { collapsed } = this.state;
return (
<div className="right-menu" style={{ width: 256 }}>
<Button
type="primary"
onClick={this.toggleCollapsed}
style={{ marginBottom: 16 }}
>
<Icon type={this.toggleCollapsed ? 'menu-unfold' : 'menu-fold'} />
</Button>
<Menu
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
mode="inline"
theme="dark"
inlineCollapsed={collapsed}
>
<SubMenu
key="sub1"
title={
<span>
<Icon type="mail" />
<span>Métérologie</span>
</span>
}
>
<Menu.Item key="5">Option 5</Menu.Item>
</SubMenu>
<SubMenu
key="sub2"
title={
<span>
<Icon type="appstore" />
<span>Chat</span>
</span>
}
>
<Menu.Item key="9">Option 9</Menu.Item>
<Menu.Item key="10">Option 10</Menu.Item>
</SubMenu>
</Menu>
</div>
);
}
}
export default RightVerticalMenu;
console errors :
Must Use destructuring state assignment[29, 19]
Missing Parentheses around multilines JSX[55, 15] and [67, 15]
I'm using a Sider component with a Menu inside which has some Submenus on it.
When my component is static, meaning not plugged to redux, just a plain component, the Menu /> and its children work as expected.
But, in my case im trying to make my menu dynamic, so in reality my component is connected to the store using Redux and to generate all the links im using mapStateToProps and then 'connect'.
When i'm using my component with Redux, for some reason the menu doesnt work as expected. The problem boils down to ANTD not removing a class, ant-menu-inline-collapsed which basically makes my the menu not show any text even when it is expanded.
To compare current behaviours vs expected, I found the ONE difference generated on the code which is basically creating the problem
Current
Closed sider:
<div class="ant-layout-sider ant-layout-sider-collapsed" style="...">
<div class="ant-layout-sider-children">
<ul class="ant-menu ant-menu-dark ant-menu-inline-collapsed ant-menu-root ant-menu-vertical" role="menu" ...>
Opened:
<div class="ant-layout ant-layout-has-sider"><div class="ant-layout-sider" style="...">
<div class="ant-layout-sider-children">
<ul class="ant-menu ant-menu-dark **ant-menu-inline-collapsed** ant-menu-root ant-menu-vertical" role="menu">
The problem here is that the the sider is opened, the menu UL is keeping the ant-menu-inline-collapsed class. In reality it should switch it to ant-menu-inline.
I cant understand why this is happening. As soon as i remove the redux logic from my component, the Menu behaviour works fine and the class in question is removed.
The moment i put the redux logic back in, for some reason ANTD doesnt remove said class.
I'm lost as to how to proceed.
Menu configuration is the standard and it should not be affected at all as far as i know.
This is my menu code, in case you want to have a quick look:
<Menu
onClick={this.handleClick}
theme="dark"
mode="inline"
defaultSelectedKeys={['1']}
selectedKeys={[this.state.current]}>
<Menu.Item key={ROUTE_DASHBOARD}>
<Tooltip placement="right">
<Link to={ROUTE_DASHBOARD}>
<Icon type="calendar" />
<span className="nav-text">Home</span>
</Link>
</Tooltip>
</Menu.Item>
<SubMenu
key='sub2'
disabled={!budgetView}
title={<span><Icon type="mail" /><span>Top Down</span></span>}>
<Menu.Item key="3">
<Link to={`${ROUTE_BUDGET}/SS/budget/${budgetId}/version/${versionName}/${versionId}/exec`}>
<Icon type="calendar" />
<span className="nav-text">Exec Recap</span>
</Link>
</Menu.Item>
<Menu.Item key="4">
<Link to={`${ROUTE_BUDGET}/SS/budget/${budgetId}/version/${versionName}/${versionId}/total`}>
<Icon type="calendar" />
<span className="nav-text">Total</span>
</Link>
</Menu.Item>
<Menu.Item key="5">
<Link to={`${ROUTE_BUDGET}/SS/budget/${budgetId}/version/${versionName}/${versionId}/women`}>
<Icon type="calendar" />
<span className="nav-text">Women</span>
</Link>
</Menu.Item>
<Menu.Item key="6">
<Link to={`${ROUTE_BUDGET}/SS/budget/${budgetId}/version/${versionName}/${versionId}/men`}>
<Icon type="calendar" />
<span className="nav-text">Men</span>
</Link>
</Menu.Item>
</SubMenu>
<SubMenu
key="sub7"
title={<span><Icon type="team" /><span>Middle Out</span></span>}>
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</SubMenu>
<SubMenu
key="sub3"
title={<span><Icon type="file" /><span>Bottom Up</span></span>}
>
<Menu.Item key="3">Buttom Up 1</Menu.Item>
<Menu.Item key="4">Buttom Up 2</Menu.Item>
<Menu.Item key="5">Buttom Up 3</Menu.Item>
</SubMenu>
<SubMenu
key="sub4"
title={<span><Icon type="area-chart" /><span>Reporting</span></span>}>
<Menu.Item key="3">Reporting-1</Menu.Item>
<Menu.Item key="4">Reporting-2</Menu.Item>
<Menu.Item key="5">Reporting-3</Menu.Item>
</SubMenu>
</Menu>