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
CodePudding user response:
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.
CodePudding user response:
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
CodePudding user response:
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