Reputation: 11
I have a nav menu and I want to run a function on the list item I click on, in order to open up a submenu. What's happening now is that I click on an item and all submenus show.I made it work before using individual values for every submenu, I was wondering though if I could make it work with a single function rather than copying and pasting the same one 2 more times. Any suggestions guys? Here's my code
import React, { useEffect } from "react";
import { useImmer } from "use-immer";
// Submenu component
import Submenu from "./Submenu";
function Navbar() {
const [state, setState] = useImmer({
menu: false
});
/*
return function menu(sub) {
setState(draft => {
draft.sub = !draft.sub;
});
};
*/
function handleSubMenu(e) {
e.preventDefault();
setState(draft => {
draft.menu = !draft.menu;
});
}
return (
<>
<li className="navbar-main__item navbar-main__item--1">
<a onClick={handleSubMenu} href="#" className=" navbar-main__link">
<span>List item 1</span>{" "}
<svg
className={
state.menu
? "navbar-main__icon navbar-main__icon--rotate-down"
: "navbar-main__icon navbar-main__icon--rotate"
}
>
<use href="img/sprite.svg#icon-chevron-thin-down" />
</svg>
</a>
<Submenu
subfirst="Item 1"
subsecond="Item 2"
subthird="Meat 3"
state={state.menu}
/>
</li>
<li className="navbar-main__item navbar-main__item--2">
<a onClick={handleSubMenu} data-id="1" href="#" className="navbar-main__link">
<span>List Item 2</span>{" "}
<svg
className={
state.menu
? "navbar-main__icon navbar-main__icon--rotate-down"
: "navbar-main__icon navbar-main__icon--rotate"
}
>
<use href="img/sprite.svg#icon-chevron-thin-down" />
</svg>
</a>
<Submenu
subfirst="Item 1"
subsecond="Item 2"
subthird="Item 3"
state={state.menu}
/>
</li>
<li className="navbar-main__item navbar-main__item--3">
<a onClick={handleSubMenu} href="#" className="navbar-main__link">
<span>List Item 3</span>{" "}
<svg
className={
state.menu
? "navbar-main__icon navbar-main__icon--rotate-down"
: "navbar-main__icon navbar-main__icon--rotate"
}
>
<use href="img/sprite.svg#icon-chevron-thin-down" />
</svg>
</a>
<Submenu
subfirst="Item 1"
subsecond="Item 2"
subthird="Item 3"
state={state.menu}
/>
</li>
</>
);
}
export default Navbar;
Upvotes: 1
Views: 382
Reputation: 1102
In order to reuse the same function for each, you'll have to modify what you're storing in state. menu
is a boolean so it can only have one of two values. However, if you store a unique identifier for each Submenu, you could change if the submenu is open based on that. For example, if each submenu had an id, and you stored that id in state, you could compare that id to the submenu's id and pass true/false for if it's open or not.
There are a few other improvements you can make to this component to make it less repetitive. There's a lot of duplication that can simplified.
import React from "react";
import { useImmer } from "use-immer";
import Submenu from "./Submenu";
const menuItems = [
{
id: 'menu1',
subfirst: "Item 1",
subsecond: "Item 2",
subthird: "Meat 3",
},
{
id: 'menu2',
subfirst: "Item 1",
subsecond: "Item 2",
subthird: "Item 3",
},
{
id: 'menu3',
subfirst: "Item 1",
subsecond: "Item 2",
subthird: "Item 3",
},
];
function Navbar() {
const [state, setState] = useImmer({ openMenuId: undefined });
function openSubMenu(menuId) {
e.preventDefault();
setState(draft => {
draft.openMenuId = menuId;
});
}
return (
<ul style={{ listStyle: 'none' }}>
{menuItems.map((menuItem, index) => (
<li className={`navbar-main__item navbar-main__item--${index}`}>
<a onClick={() => openSubMenu(menuItem.id)} href="#" className="navbar-main__link">
<span>List item {index}</span>
<svg
className={`navbar-main__icon navbar-main__icon--rotate${state.openMenuId === menuItem.id ? '-down' : ''}`}
>
<use href="img/sprite.svg#icon-chevron-thin-down" />
</svg>
</a>
<Submenu
subfirst={menuItem.subfirst}
subsecond={menuItem.subsecond}
subthird={menuItem.subthird}
isOpen={state.openMenuId === menuItem.id}
/>
</li>
))}
</ul>
);
}
export default Navbar;
That was just a quick pass over though. useImmer is probably overkill for this case, unless you plan on adding more to the state.
Upvotes: 1