Home > Blockchain >  Open one Submenu at a time React js
Open one Submenu at a time React js

Time:02-22

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
  • Related