Investigué e intenté implementar algunas de las soluciones proporcionadas, pero fallé al intentar lograrlo. Pude hacer mi menú desplegable y hacer clic para que cada submenú se abra y se cierre cuando se haga clic en su elemento principal. Me gustaría tener un submenú abierto para cerrar cuando se hace clic en un menú diferente, por lo que no tengo todos apilados en la barra de menú. ¿Podría alguien señalar cómo puedo lograr esto? Gracias por ayudarme.
Menú.js
import React from 'react' import MenuItem from '../MenuItem'; import { SidebarData } from '../../helpers/SidebarData'; import * as C from './styles'; const Menu = () => { return ( <C.Container> <C.MenuArea> {SidebarData.map((item, index) => { return <MenuItem item={item} key={index} />; })} </C.MenuArea> </C.Container> ) }; export default MenuMenuItem.js
import React, { useState } from 'react'; import { NavLink } from 'react-router-dom'; import * as C from './styles'; const MenuItem = ({ item }) => { const [opened, setOpened] = useState(false); const showSubnav = () => setOpened(!opened); return ( <C.NavUnlisted> <NavLink to={item.path} onClick={item.subNav && showSubnav} activeClassName='current' exact={item.path === '/' ? true : false} > <C.SidebarLink> <div> {item.icon} <C.SidebarLabel>{item.title}</C.SidebarLabel> </div> <div> {item.subNav && opened ? item.iconOpened : item.subNav ? item.iconClosed : null} </div> </C.SidebarLink> </NavLink> {opened && item.subNav.map((item, index) => { return ( <NavLink to={item.path} key={index} activeClassName='current' > <C.DropdownLink> {item.icon} <C.SidebarLabel>{item.title}</C.SidebarLabel> </C.DropdownLink> </NavLink> ); })} </C.NavUnlisted> ); }; export default MenuItem;Pude encontrar una solución. Agregué una identificación para cada menú para poder cambiar el estado en función de él. Tenía todo el menú en un solo componente. No parecía ser necesario tener un componente separado para el elemento del menú. Aquí está mi código:
import React, { useState } from 'react' import { SidebarData } from '../../helpers/SidebarData'; import * as C from './styles'; import { NavLink } from "react-router-dom"; const Menu = () => { const [open, setOpen] = useState(''); const toggle = (id) => setOpen(id); return ( <C.Container> <C.MenuArea> {SidebarData.map((item, index) => ( <C.NavUnlisted key={index}> <NavLink to={item.path} onClick={() => toggle(item.navId)} activeClassName='current' exact={item.path === '/' ? true : false}> <C.SidebarLink> <div> {item.icon} <C.SidebarLabel>{item.title}</C.SidebarLabel> </div> </C.SidebarLink> </NavLink> {open === item.navId && ( <div> {item.subNav.map((item, index) => ( <NavLink to={item.path} key={index} activeClassName='current' > <C.DropdownLink> {item.icon} <C.SidebarLabel>{item.title}</C.SidebarLabel> </C.DropdownLink> </NavLink> ))} </div> )} </C.NavUnlisted> ))} </C.MenuArea> </C.Container> ) }; export default MenuIntente cerrar el menú cuando haga clic fuera de su componente de menú, si es una solución que le interesa, puede obtener más información sobre cómo lograr esto en reaccionar allí:
Una forma elegante de manejar esto sería realizar un seguimiento del submenú actualmente abierto en el componente Menu y mostrar/ocultar los submenús dependiendo de un apoyo transmitido desde el componente principal.
import React from 'react' import MenuItem from '../MenuItem'; import { SidebarData } from '../../helpers/SidebarData'; import * as C from './styles'; const Menu = () => { const [currentlyOpen, setCurrentlyOpen] = useState(null); return ( <C.Container> <C.MenuArea> {SidebarData.map((item, index) => { return <MenuItem item={item} key={index} isOpen={index === currentlyOpen} onClick={() => setCurrentlyOpen(index)} />; })} </C.MenuArea> </C.Container> ) }; export default Menu Luego llamaría a handleClick con el índice respectivo en MenuItem.js .
import React, { useState } from 'react'; import { NavLink } from 'react-router-dom'; import * as C from './styles'; const MenuItem = ({ item, onClick: handleClick }) => { const [opened, setOpened] = useState(false); const showSubnav = () => setOpened(!opened); return ( <C.NavUnlisted> <NavLink to={item.path} onClick={item.subNav && handleClick} activeClassName='current' exact={item.path === '/' ? true : false} > <C.SidebarLink> <div> {item.icon} <C.SidebarLabel>{item.title}</C.SidebarLabel> </div> <div> {item.subNav && opened ? item.iconOpened : item.subNav ? item.iconClosed : null} </div> </C.SidebarLink> </NavLink> {opened && item.subNav.map((item, index) => { return ( <NavLink to={item.path} key={index} activeClassName='current' > <C.DropdownLink> {item.icon} <C.SidebarLabel>{item.title}</C.SidebarLabel> </C.DropdownLink> </NavLink> ); })} </C.NavUnlisted> ); }; export default MenuItem;