Home > database >  How to close an opened menu with submenu items when another menu is clicked
How to close an opened menu with submenu items when another menu is clicked

Time:08-12

The Problem

I have a sidebar with menus and some of the menus has submenus. I would like to close any opened menu with submenus when a different menu is clicked.

Stack

Written in React with react hooks

Sidebar

  const [open, setOpen] = useState(true);

  return (
    <div>
      <ul>
        {SidebarData.map((item, index) => {
          return (
            <SubMenu
              item={item}
              key={index}
              titleOpen={!open}
              dropOpen={open}
              subMenuOpen={open}
            />
          );
        })}
      </ul>
    </div>
  );
}

SubMenu

function SubMenu({ item, titleOpen, dropOpen, subMenuOpen }) {
  const [subnav, setSubnav] = useState(false);

  const showSubnav = () => setSubnav(!subnav);

  return (
    <div>
      <ul>
        <Link to={item.path} onClick={item.subNav && showSubnav}>
          <li>
            <span>{item.icon}</span>
            <span>
              {item.title}
            </span>
            {item.subNav && dropOpen && (
              <KeyboardArrowDownIcon/>
            )}
          </li>
        </Link>

        {subnav &&
          subMenuOpen &&
          item.subNav.map((item, index) => {
            return (
              <ul>
                <Link to={item.path} key={index}>
                  <li>
                    <div>{item.title}</div>
                  </li>
                </Link>
              </ul>
            );
          })}
      </ul>
    </div>
  );
}

Each menu has a unique id

CodePudding user response:

To achieve this you would need to move state of opened menus outside of the Submenu component and consume it as a prop instead.

Sidebar

const [openedMenuIndex, setOpenedMenuIndex] = useState(0);

return (
   <div>
      <ul>
         {SidebarData.map((item, index) => (
             <SubMenu
                item={item}
                key={index}
                isOpened={openedMenuIndex === index}
                onClickSubnav={() => setOpenedMenuIndex(index)}
             />
        
         )}
      </ul>
   </div>
 );
}

Submenu

function SubMenu({ item, isOpened, onClickSubnav}) {
    return (
      <div>
        <ul>
          <Link to={item.path} onClick={item.subNav && onClickSubnav}>
  ....

  // later in the code show/hide subnav based on value in isOpened property

CodePudding user response:

There are probably a couple ways to do it, but I think the easiest would be to have a useState to keep track of the menu item that is expanded:

const [expanded, setExpanded] = React.useState("name of default menu item to expand"); // or React.useState(null) to collapse all by default

and then use that variable when determining whether or not to show something (and how you do it is up to you), e.g.:

<SubMenuItem visible={expanded === 'subitem3'} onChange={setExpanded('subitem3')}>

visible is probably not a real property, but whatever it is that you use as the condition to determine whether the subitem is in an expanded state or not. Changing expanded then re-evaluates all the other submenu item conditions, which will collapse them.

  • Related