首页 > 解决方案 > 带有反应的导航菜单

问题描述

我有一个导航菜单,我想在单击的列表项上运行一个功能,以打开一个子菜单。现在发生的事情是我单击一个项目并显示所有子菜单。我在为每个子菜单使用单独的值之前使其工作,我想知道是否可以使用单个函数而不是复制和粘贴相同的函数 2更多次。有什么建议吗?这是我的代码

import React, { useEffect } from "react";
import { useImmer } from "use-immer";

// Submenu component
import Submenu from "./Submenu";

function Navbar() {
  const [state, setState] = useImmer({
    menu: false
  });
  /*
  return function menu(sub) {
    setState(draft => {
      draft.sub = !draft.sub;
    });
  };
  */

  function handleSubMenu(e) {
    e.preventDefault();
    setState(draft => {
      draft.menu = !draft.menu;
    });
  }

  return (
    <>
      <li className="navbar-main__item navbar-main__item--1">
        <a onClick={handleSubMenu} href="#" className=" navbar-main__link">
          <span>List item 1</span>{" "}
          <svg
            className={
              state.menu
                ? "navbar-main__icon  navbar-main__icon--rotate-down"
                : "navbar-main__icon  navbar-main__icon--rotate"
            }
          >
            <use href="img/sprite.svg#icon-chevron-thin-down" />
          </svg>
        </a>

        <Submenu
          subfirst="Item 1"
          subsecond="Item 2"
          subthird="Meat 3"
          state={state.menu}
        />
      </li>

      <li className="navbar-main__item navbar-main__item--2">
        <a onClick={handleSubMenu} data-id="1" href="#" className="navbar-main__link">
          <span>List Item 2</span>{" "}
          <svg
            className={
              state.menu
                ? "navbar-main__icon  navbar-main__icon--rotate-down"
                : "navbar-main__icon  navbar-main__icon--rotate"
            }
          >
            <use href="img/sprite.svg#icon-chevron-thin-down" />
          </svg>
        </a>

        <Submenu
          subfirst="Item 1"
          subsecond="Item 2"
          subthird="Item 3"
          state={state.menu}
        />
      </li>

      <li className="navbar-main__item navbar-main__item--3">
        <a onClick={handleSubMenu} href="#" className="navbar-main__link">
          <span>List Item 3</span>{" "}
          <svg
            className={
              state.menu
                ? "navbar-main__icon  navbar-main__icon--rotate-down"
                : "navbar-main__icon  navbar-main__icon--rotate"
            }
          >
            <use href="img/sprite.svg#icon-chevron-thin-down" />
          </svg>
        </a>
        <Submenu
          subfirst="Item 1"
          subsecond="Item 2"
          subthird="Item 3"
          state={state.menu}
        />
      </li>
     </>
    );
}

export default Navbar;

标签: htmlreactjs

解决方案


为了对每个函数重用相同的函数,您必须修改您在状态中存储的内容。menu是一个布尔值,所以它只能有两个值之一。但是,如果您为每个子菜单存储一个唯一标识符,则可以根据该标识符更改子菜单是否打开。例如,如果每个子菜单都有一个 id,并且您将该 id 存储在 state 中,您可以将该 id 与子菜单的 id 进行比较,并传递 true/false 以判断它是否打开。

您可以对该组件进行一些其他改进,以减少重复性。有很多重复可以简化。

import React from "react";
import { useImmer } from "use-immer";
import Submenu from "./Submenu";

const menuItems = [
  {
    id: 'menu1',
    subfirst: "Item 1",
    subsecond: "Item 2",
    subthird: "Meat 3",
  },
  {
    id: 'menu2',
    subfirst: "Item 1",
    subsecond: "Item 2",
    subthird: "Item 3",
  },
  {
    id: 'menu3',
    subfirst: "Item 1",
    subsecond: "Item 2",
    subthird: "Item 3",
  },
];

function Navbar() {
  const [state, setState] = useImmer({ openMenuId: undefined });

  function openSubMenu(menuId) {
    e.preventDefault();
    setState(draft => {
      draft.openMenuId = menuId;
    });
  }

  return (
    <ul style={{ listStyle: 'none' }}>
      {menuItems.map((menuItem, index) => (
        <li className={`navbar-main__item navbar-main__item--${index}`}>
          <a onClick={() => openSubMenu(menuItem.id)} href="#" className="navbar-main__link">
            <span>List item {index}</span>
            <svg
              className={`navbar-main__icon  navbar-main__icon--rotate${state.openMenuId === menuItem.id ? '-down' : ''}`}
            >
              <use href="img/sprite.svg#icon-chevron-thin-down" />
            </svg>
          </a>
          <Submenu
            subfirst={menuItem.subfirst}
            subsecond={menuItem.subsecond}
            subthird={menuItem.subthird}
            isOpen={state.openMenuId === menuItem.id}
          />
        </li>
      ))}
    </ul>
  );
}

export default Navbar;

不过,这只是一个快速的传递。对于这种情况, useImmer 可能是矫枉过正,除非您打算向状态添加更多内容。


推荐阅读