I have researched and tried to implement some of the solutions provided but I failed when trying to achieve this. I was able to make my dropdown menu and click so each submenu will open and close when its parent is clicked. I would like to have an opened submenu to be closed when a different menu is clicked, so I don´t have all of them stacked at the menu bar. Could someone point out how can I achieve this? Thank you for helping me.
Menu.js
import React from 'react'
import MenuItem from '../MenuItem';
import { SidebarData } from '../../helpers/SidebarData';
import * as C from './styles';
const Menu = () => {
return (
<C.Container>
<C.MenuArea>
{SidebarData.map((item, index) => {
return <MenuItem item={item} key={index} />;
})}
</C.MenuArea>
</C.Container>
)
};
export default Menu
MenuItem.js
import React, { useState } from 'react';
import { NavLink } from 'react-router-dom';
import * as C from './styles';
const MenuItem = ({ item }) => {
const [opened, setOpened] = useState(false);
const showSubnav = () => setOpened(!opened);
return (
<C.NavUnlisted>
<NavLink to={item.path} onClick={item.subNav && showSubnav} activeClassName='current' exact={item.path === '/' ? true : false} >
<C.SidebarLink>
<div>
{item.icon}
<C.SidebarLabel>{item.title}</C.SidebarLabel>
</div>
<div>
{item.subNav && opened
? item.iconOpened
: item.subNav
? item.iconClosed
: null}
</div>
</C.SidebarLink>
</NavLink>
{opened &&
item.subNav.map((item, index) => {
return (
<NavLink to={item.path} key={index} activeClassName='current' >
<C.DropdownLink>
{item.icon}
<C.SidebarLabel>{item.title}</C.SidebarLabel>
</C.DropdownLink>
</NavLink>
);
})}
</C.NavUnlisted>
);
};
export default MenuItem;
CodePudding user response:
Try to close the menu when you click outside your menu component, if it's a solution you're interested in you can learn more about how to achieve this in react there :
https://stackoverflow.com/a/42234988/16956436
CodePudding user response:
An elegant way to handle this would be to keep track of the currently opened submenu in the Menu
component and displaying/hiding the submenus depending on a prop passed down from the parent component.
import React from 'react'
import MenuItem from '../MenuItem';
import { SidebarData } from '../../helpers/SidebarData';
import * as C from './styles';
const Menu = () => {
const [currentlyOpen, setCurrentlyOpen] = useState(null);
return (
<C.Container>
<C.MenuArea>
{SidebarData.map((item, index) => {
return <MenuItem item={item} key={index} isOpen={index === currentlyOpen} onClick={() => setCurrentlyOpen(index)} />;
})}
</C.MenuArea>
</C.Container>
)
};
export default Menu
You would then call handleClick
with the respective index in MenuItem.js
.
import React, { useState } from 'react';
import { NavLink } from 'react-router-dom';
import * as C from './styles';
const MenuItem = ({ item, onClick: handleClick }) => {
const [opened, setOpened] = useState(false);
const showSubnav = () => setOpened(!opened);
return (
<C.NavUnlisted>
<NavLink to={item.path} onClick={item.subNav && handleClick} activeClassName='current' exact={item.path === '/' ? true : false} >
<C.SidebarLink>
<div>
{item.icon}
<C.SidebarLabel>{item.title}</C.SidebarLabel>
</div>
<div>
{item.subNav && opened
? item.iconOpened
: item.subNav
? item.iconClosed
: null}
</div>
</C.SidebarLink>
</NavLink>
{opened &&
item.subNav.map((item, index) => {
return (
<NavLink to={item.path} key={index} activeClassName='current' >
<C.DropdownLink>
{item.icon}
<C.SidebarLabel>{item.title}</C.SidebarLabel>
</C.DropdownLink>
</NavLink>
);
})}
</C.NavUnlisted>
);
};
export default MenuItem;