Skip to content
Advertisement

React show toggle showing all children

Im using react.js and im trying to have a <ul> with each <li> having a child <ul>. When an icon in the <li> is clicked Im trying to show its child <ul>. The current way I have it its showing ALL the <li>‘s children instead of just its own corresponding child.

    const FooterMenu = (props) => {

    const { menuName } = props;
    const [menu, setMenu] = useState([]);
    const [showDetails, setShowDetails] = useState(false);

    useEffect(() => {
        if (menuName) {
            axios.get(``)
                .then(response => {
                   setMenu(response.data);
                }).catch(error => {
                    console.log('[Page] error', error); //TO-DO: remove before prod deployment
                    //TO-DO: add redirect to error page
                })
        }
        
    }, [menuName]);

    return (
        <ul>
            { menu.map(row => {
                return (
                    <li className="footer-menu-icon footer-menu-item">
                        <i className={`fas showSubLinks ${row.SubMenus.length >= 1 ? (showDetails ? 'fa-minus' : 'fa-plus') : 'fa-angle-right'}`} onClick={() => setShowDetails(() => !showDetails)}></i>
                        <a href={row.MenuLink} target={row.LinkTarget ? row.LinkTarget : '_self'}>{row.MenuText}</a>
                        {row.SubMenus.length >= 1 && showDetails  ? (
                            <ul className="subMenu-items">
                                {
                                    row.SubMenus.map(row => {
                                        return (
                                            <li>
                                                <a href={row.MenuLink} target={(row.LinkTarget) ? row.LinkTarget : '_self'}>{row.MenuText}</a>
                                            </li>
                                        )
                                    })
                                }
                            </ul>
                        ) : (
                            <></>
                        )}
                    </li>
                )
            })}
        </ul>
    );
};

export default FooterMenu;

I know the showDetails is to blame but cant seem to wrap my head around how to do this

enter image description here

enter image description here

Advertisement

Answer

You can handle the the showDetails in the menu array itself as a property like below, when the menu is loaded it will have the default value which is false and after that the buttons would toggle it to true and false

const Menu = () => {
  const [menu, setMenu] = useState([
    {
      MenuText: "Submenu",
      SubMenus: [
        {
          MenuLink: "#",
          MenuText: "Submenu"
        }
      ]
    },

    {
      MenuText: "Submenu1",
      SubMenus: [
        {
          MenuLink: "#",
          MenuText: "Submenu"
        }
      ]
    }
  ]);

  return (
    <ul>
      {menu.map((row, i) => {
        return (
          <li className="footer-menu-icon footer-menu-item">
            <i
              className={`fas showSubLinks ${
                row.SubMenus.length >= 1
                  ? row.showDetails
                    ? "fa-minus"
                    : "fa-plus"
                  : "fa-angle-right"
              }`}
              onClick={() => {
                const updatedMenu = [...menu];
                updatedMenu[i].showDetails = !updatedMenu[i].showDetails;
                setMenu(updatedMenu);
              }}
            ></i>
            <a
              href={row.MenuLink}
              target={row.LinkTarget ? row.LinkTarget : "_self"}
            >
              {row.MenuText}
            </a>
            {row.SubMenus.length >= 1 && row.showDetails ? (
              <ul className="subMenu-items">
                {row.SubMenus.map((row) => {
                  return (
                    <li>
                      <a
                        href={row.MenuLink}
                        target={row.LinkTarget ? row.LinkTarget : "_self"}
                      >
                        {row.MenuText}
                      </a>
                    </li>
                  );
                })}
              </ul>
            ) : (
              <></>
            )}
          </li>
        );
      })}
    </ul>
  );
};
Advertisement