Reputation: 434
I want to close all other open SubMenu when the user opens a SubMenu.
Can anyone help me to find a solution?
My code:
Menu.tsx ->
const Menu: React.FC = ({ data }) => {
return (
<nav className={styles.headerMenu}>
{
data.map((item, index) => <MenuItem key={index} item={item} /> )
}
</nav>
)
}
MenuItem.tsx ->
const MenuItem: React.FC = ({ item }) => {
let [subMenuOpened, setSubMenuOpened] = useState<boolean>(false);
const switchMenu = (condition) => setSubMenuOpened(condition !== null ? condition : !subMenuOpened)
const SubMenu: React.FC = () => { /* Code to render submenu */ }
return (
<section onMouseEnter={()=> item.subMenu && switchMenu(true)} onMouseLeave={() => item.subMenu && switchMenu(false)}>
<a href={item.href}>{item.title}</a>
//Render SubMenu if item has submenu and it is open
{ (item.subMenu && subMenuOpened) && <SubMenu /> }
</section>
)
}
Upvotes: 1
Views: 1252
Reputation: 4870
@Nikki9696 answered your question in a comment:
Generally, if a sibling needs to know about other sibling state, you move the state up to the parent. So, you'd keep track of which submenu was open in the Menu component, not the MenuItem, and close all but the selected one there.
so I will show you an example of what they meant:
const Menu: React.FC = ({ data }) => {
const keys = data.map(function(item,key) { return { key:key, close: null, item: item}});
onOpen=(key)=>{
// this will close all menus except the current one
keys.forEach(x=>{
if (x.key !== key && x.close !== null)
x.close(); // Close should be set by child eg MenuItem.
})
}
return (
<nav className={styles.headerMenu}>
{
keys.map((item, index) => <MenuItem onOpen={onOpen} key={index} item={item} /> )
}
</nav>
)
}
const MenuItem: React.FC = ({ item, onOpen }:{item: any, onOpen:Function}) => {
let [subMenuOpened, setSubMenuOpened] = useState<boolean>(false);
item.close = ()=> { setSubMenuOpened(false); } /// this is so the parent will trigger close
const switchMenu = (condition) => setSubMenuOpened(condition !== null ? condition : !subMenuOpened)
useEffect(() =>{
if (subMenuOpened)
onOpen(item.key); // trigger parent
}, [subMenuOpened]);
const SubMenu: React.FC = () => { /* Code to render submenu */ }
return (
<section onMouseEnter={()=> item.item.subMenu && switchMenu(true)} onMouseLeave={() => item.subMenu && switchMenu(false)}>
<a href={item.item.href}>{item.item.title}</a>
//Render SubMenu if item has submenu and it is open
{ (item.item.subMenu && subMenuOpened) && <SubMenu /> }
</section>
)
}
Upvotes: 2