I am new to React JS and i am creating Sidebar Menu with Submenu for my Project.
Problem : When i try to open Submenu, All Submenus are getting open.
Here is the Codesandbox
I am open to other solutions as well. Any Help is much appreciated. Thanks in Advance.
App.js
import Menu from "./components/Menu/Menu";
export default function App() {
return <Menu />;
}
Menu.js
import React, {useState} from 'react'
import SubMenu from './SubMenu'
import MenuItems from './menuData'
const Menu = () => {
const [toggle, setToggle] = useState(false)
const clickHandler = () => {
console.log(`clicked`)
setToggle(!toggle)
}
return (
<nav>
<ul>
{
MenuItems.map((item) => {
return (
<li key={item.menuname} onClick={item.submenu && clickHandler}>
{item.menuname}
{item.submenu && toggle ? <SubMenu dropDownItem={item.submenu} /> : null}
</li>
)
})
}
</ul>
</nav>
)
}
export default Menu
SubMenu.js
import React from 'react'
const SubMenu = ({dropDownItem}) => {
return (
<div className='drop-down'>
<ul>
{dropDownItem.map((item) => {
return <li key={item.submenuname}>{item.submenuname}</li>
})}
</ul>
</div>
)
}
export default SubMenu
menuData.js
const MenuItems = [
{
"menuname": 'Home',
"submenu": [
{"submenuname": "Home Child 1"},
{"submenuname": "Home Child 2"},
{"submenuname": "Home Child 3"}
]
},
{
"menuname": 'About',
"submenu": [
{"submenuname": "About Child 1"},
{"submenuname": "About Child 2"},
{"submenuname": "About Child 3"}
]
},
{
"menuname": 'Contact'
}
]
export default MenuItems
The problem is happening because you have one single toggle state for all items. A possible solution might be to define the state in each single ItemMenu and then u can check for the state to show or hide the Submenu item.
Like this:
const Menu = () => {
return (
<nav>
<ul>
{MenuItems.map((item) => {
return (
<li key={item.menuname}>
<MenuItem item={item} />
</li>
);
})}
</ul>
</nav>
);
};
And this is the MenuItem :
import React, { useState } from "react";
const MenuItem = ({ item }) => {
const [isSubMenuShow, setIsSubMenuShow] = useState(false);
return (
<div>
<div onClick={() => setIsSubMenuShow(!isSubMenuShow)}>
{item.menuname}
</div>
{item.submenu && isSubMenuShow && <SubMenu dropDownItem={item.submenu} />}
</div>
);
};
const SubMenu = ({ dropDownItem }) => {
return (
<div className="drop-down">
<ul>
{dropDownItem.map((item) => {
return <li key={item.submenuname}>{item.submenuname}</li>;
})}
</ul>
</div>
);
};
export default MenuItem;
Hope that this did help you.
it's because you set a general state for handle toggle sub menus, you should change your state for example like below
const [toggle, setToggle] = useState(null)
const clickHandler = (menuId) => {
console.log(`clicked`)
setToggle(menuId)
}
return (
<nav>
<ul>
{
MenuItems.map((item) => {
return (
<li key={item.menuname} onClick={clickHandler(item.id)}>
{item.menuname}
{item.submenu && toggle == item.id ? <SubMenu dropDownItem={item.submenu} /> : null}
</li>
)
})
}
</ul>
</nav>
)
}
I gave you an example and you can set any unique value instead of item id and pass it to you handler to set in your state
You need an array for every submenu indexing and give it perspective index.
import React, {useState} from 'react'
import SubMenu from './SubMenu'
import MenuItems from './menuData'
const Menu = () => {
const [toggle, setToggle] = useState([])
const clickHandler = (i) => {
let tempToggle = [...toggle]
if(tempToggle[i]){
tempToggle[i]=false
}
else{
tempToggle[i]=true
}
setToggle(tempToggle)
}
return (
<nav>
<ul>
{
MenuItems.map((item,i) => {
return (
<li key={item.menuname} onClick={item.submenu && clickHandler}>
{item.menuname}
{item.submenu && toggle[i] ? <SubMenu dropDownItem={item.submenu} /> : null}
</li>
)
})
}
</ul>
</nav>
)
}
export default Menu