I am designing a responsive mega navigation bar using reactjs. It's working for desktop device but on mobile view, I could not able to show or hide sub menu when its associated parent menu is clicked. This is what I am trying to do
const menus = [
{ id: 1, name: "Home", link: "/" },
{
id: 3,
name: "New",
children: [{ id: 1, name: "New Arrival", link: "/new" }]
},
{
id: 2,
name: "Shop",
children: [
{
id: 1,
name: "Men's Fashion",
children: [
{
id: 1,
name: "Polo",
link: "/polo"
},
{ id: 2, name: "Tees", link: "/tees" }
]
},
{
id: 2,
name: "Women Fashion",
children: [
{
id: 1,
name: "Shorts",
link: "/shorts"
},
{
id: 2,
name: "Tees",
link: "/women/tees"
}
]
}
]
}
];
const MegaMenu = () => {
const [active, setActive] = React.useState(false);
const [toggle, setToggle] = React.useState(false);
const [activeMenuName, setActiveMenuName] = React.useState("");
const handleMainMenuClick = () => {
setActive(!active);
};
const toggleDrawer = () => {
setToggle(!toggle);
};
const hideSubMenu = () => {
setActive(!active);
};
const handleMenuName = (menuName) => {
setActiveMenuName(menuName);
};
return (
<>
<header className="header">
<div className="container">
<div className="row v-center">
<div className="header-item item-left">
<div className="logo">
<a href="#">Brand</a>
</div>
</div>
{/* menu start here */}
<div className="header-item item-center">
<div
className={`menu-overlay ${toggle ? "active" : ""}`}
onClick={toggleDrawer}
></div>
<nav className={`menu ${toggle ? "active" : ""}`}>
<div className={`mobile-menu-head ${toggle ? "active" : ""}`}>
<div className="go-back" onClick={hideSubMenu}>
Back
</div>
<div className="current-menu-title">{activeMenuName}</div>
<div className="mobile-menu-close" onClick={toggleDrawer}>
×
</div>
</div>
<ul className="menu-main" onClick={handleMainMenuClick}>
{menus.map((menu) => {
return (
<li
key={menu.id}
className={
menu.children ? "menu-item-has-children" : ""
}
onClick={() => handleMenuName(menu.name)}
>
{menu.link ? (
<a href={menu.link}>
{menu.name} <i class="fa fa-angle-down"></i>
</a>
) : (
<a href="#">{menu.name}</a>
)}
{menu.children && (
<div
className={`sub-menu mega-menu mega-menu-column-4 ${
active ? "active" : ""
}`}
>
{menu.children.map((child) => {
return (
<div
className="list-item text-center"
key={child.id}
>
<a href="#">
<img src="img/p1.jpg" alt="new Product" />
<h4 className="title">{child.name}</h4>
</a>
</div>
);
})}
</div>
)}
</li>
);
})}
</ul>
</nav>
</div>
<div className="header-item item-right">
<a href="#">
<i className="fas fa-search"></i>
</a>
<a href="#">
<i className="far fa-heart"></i>
</a>
<a href="#">
<i className="fas fa-shopping-cart"></i>
</a>
{/* mobile menu trigger */}
<div className="mobile-menu-trigger" onClick={toggleDrawer}>
<span></span>
</div>
</div>
</div>
</div>
</header>
</>
);
};
export default MegaMenu;
I have a code on sandbox as well and here it is
https://codesandbox.io/s/weathered-resonance-9n2hr?file=/src/mega-menu/index.js:50-4734
You should set active
only to the activeMenuName
that is clicked. Also when click go back
you should reset activeMenuName
to the default state. Also, I check if toggle
is enabled so only onClick
events are enabled and vice versa.
Check my code it's tested.
const MegaMenu = () => {
const [active, setActive] = React.useState(false);
const [toggle, setToggle] = React.useState(false);
const [activeMenuName, setActiveMenuName] = React.useState("");
const handleMainMenuClick = () => {
setActive(!active);
};
const toggleDrawer = () => {
setActiveMenuName("");
setToggle(!toggle);
};
const hideSubMenu = () => {
setActiveMenuName("");
};
const handleMenuName = (menuName) => {
setActiveMenuName(menuName);
};
const renderLiComp = (menu) =>{
if(toggle){
return <li
key={menu.id}
className={ menu.children ? "menu-item-has-children" : "" }
onClick={() =>handleMenuName(menu.name)}
>
{menu.link
? (<a href={menu.link}>{menu.name} <i className="fa fa-angle-down"></i></a>)
: (<a href="#">{menu.name}</a>)}
{activeMenuName && getSelectedChildren()}
</li>;
}else{
return <li
key={menu.id}
className={ menu.children ? "menu-item-has-children" : "" }
onMouseEnter={()=>handleMenuName(menu.name)}
>
{menu.link
? (<a href={menu.link}>{menu.name} <i className="fa fa-angle-down"></i></a>)
: (<a href="#">{menu.name}</a>)}
{activeMenuName && getSelectedChildren()}
</li>;
}
}
const renderListElements = () =>{
return menus.map(renderLiComp);
}
const renderChildren = (childs) =>{
const children = childs.map(x =>
<div className="list-item text-center" key={x.id}>
<a href="#"><img src="img/p1.jpg" alt="new Product" />
<h4 className="title">{x.name}</h4>
</a>
</div>
);
return children;
}
const getSelectedChildren = () =>{
return menus.map(x => {
let selected;
if(x.name === activeMenuName){
if(x.children){
selected = <div key={x.id} className='sub-menu mega-menu mega-menu-column-4 active'>{renderChildren(x.children)}</div>;
}else{
selected = <div key={x.id} className='sub-menu mega-menu mega-menu-column-4 active'></div>;
}
}
return selected;
});
}
return (
<>
<header className="header">
<div className="container">
<div className="row v-center">
<div className="header-item item-left">
<div className="logo">
<a href="#">Brand</a>
</div>
</div>
{/* menu start here */}
<div className="header-item item-center">
<div
className={`menu-overlay ${toggle ? "active" : ""}`}
onClick={toggleDrawer}
></div>
<nav className={`menu ${toggle ? "active" : ""}`}>
<div className={`mobile-menu-head ${toggle ? "active" : ""}`}>
<div className="go-back" onClick={hideSubMenu}>
Back
</div>
<div className="current-menu-title">{activeMenuName}</div>
<div className="mobile-menu-close" onClick={toggleDrawer}>
×
</div>
</div>
<ul className="menu-main" onClick={handleMainMenuClick}>
{renderListElements()}
</ul>
</nav>
</div>
The sandbox Link https://codesandbox.io/s/nifty-cloud-kuryf?file=/src/mega-menu/index.js
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.