Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React How to Individually Target li State

I am somewhat new to react and I am building a navigation menu where I target the ul and li components using the map() function with index to avoid duplicating code. Whenever I click to open one component all components open instead of an individual one. I know the issue is probably in me not targeting the components correctly so any help will be appreciated.
Here is the code:

...react icon and state imports

const Navbar = () => {
    const [subMenuOpen, setSubmenuOpen] = useState(false);
    const menu = [
        { 
            title: "Management",
            submenu: true,
            icon: <FaUserTie/>,
            submenuItems: [
                { title: "MGMT Cockpit" },
                { title: "P&L by Month" },
                { title: "B/O Report" },
                { title: "User List" },
            ],
        },
        { 
            title: "Tools",
            submenu: true,
            icon: <BsTools/>,
            submenuItems: [
                { title: "Inventory" },
                { title: "Damages" },
                { title: "MGMGT Tools" },
                { title: "Plan Tools" },
                { title: "Sales Tools" },
                { title: "Planning Tools" }, 
            ]
        }, 
    ];

    return (
        <div className="flex">
            <div className="bg-primary h-screen w-64 p-3 relative overflow-y-scroll">
                {menu.map((item, index) => <sidebarItem key={index} sidebarItem = {index}/>)}
                <ul className="pt-2">
                    {menu.map((menu, index) => (
                        <>
                            <li className="
                                text-gray-300 text-lg flex item-center gap-x-4 cursor-pointer p-2 my-4
                                hover:bg-slate-50 hover:text-primary hover:rounded-lg duration-500"
                                onClick={() => setSubmenuOpen(!subMenuOpen)}> //Fix this???
                                <span className="text-2xl block float-left">
                                    {menu.icon ? menu.icon : <RiDashboardFill/>}
                                </span>
                                <span className="text-base font-medium flex-1">{menu.title}</span>
                                {menu.submenu && (
                                    <BsChevronDown className={`${subMenuOpen && "rotate-180"} duration-300`}/>
                                )}
                            </li>
                            {menu.submenu && subMenuOpen && (
                                <ul>
                                    {menu.submenuItems.map((submenuItem, index) => (
                                        <li key={index} className="text-gray-300 text-md gap-x-4 px-5 my-3">
                                            {submenuItem.title}
                                        </li>
                                    ))}
                                </ul>
                            )}
                        </>
                    ))}
                </ul>

            </div>
            
        </div>
    )
}

export default Navbar

App.js just imports this Navbar so I didn’t include the code for that.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

You have different possibilities of open submenus (since you have multiple menu types), so you should have state that reflects that. A plain true/false state won’t be able to store enough information. One approach would be an array of submenu indices that are open.

const [submenuIndicesOpen, setSubmenuIndicesOpen] = useState([]);

Then examine the indices when iterating to determine what should be shown and how to call setSubmenuItemsOpen when toggling.

<ul className="pt-2">
    {menu.map((menuItem, index) => ( /* don't shadow the menu variable here */
        <>
            <li className="
                text-gray-300 text-lg flex item-center gap-x-4 cursor-pointer p-2 my-4
                 hover:bg-slate-50 hover:text-primary hover:rounded-lg duration-500"
                onClick={() => setSubmenuOpen(
                    submenuIndicesOpen.includes(index)
                    ? submenuIndicesOpen.filter(i => i !== index)
                    : [...submenuIndicesOpen, index]
                )}>
{menuItem.submenu && submenuIndicesOpen.includes(index) && (

If only one submenu can be open at a time, you could instead have a state that’s just a single number, the index of the open submenu.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading