首页 > 解决方案 > 单击另一个元素时切换元素上的类

问题描述

我有这个组件在反应。每当我单击带有类“btn”的标签时,我想在同一个 li 元素中添加/切换类“open”到带有类“smenu”的 div。我像下面这样天真地实现了它,但我相信应该有另一种更有效的方法。任何提示将不胜感激。提前致谢

import React, { useState } from "react";

const AccordioMenu = () => {
  const [activeP, setActiveP] = useState(false);
  const [activeM, setActiveM] = useState(false);

  const toggleActiveP = () => {
    setActiveP(!activeP);
  };
  const toggleActiveM = () => {
    setActiveM(!activeM);
  };

  let btnclassesP = ['smenu']
  if(activeP){
    btnclassesP.push('open')
  }
  let btnclassesM = ['smenu']
  if(activeM){
    btnclassesM.push('open')
  }
  return (
    <div className="middle">
      <div className="menu">
        <li className="item" id="profile">
          <a className='btn' href="#" onClick={toggleActiveP}>
            Profile
          </a>
          <div className={btnclassesP.join(' ')}>
            <a href="">Posts</a>
            <a href="">Pictures</a>
          </div>
        </li>
        <li className="item" id="messages">
          <a className="btn" href="#" onClick={toggleActiveM}>
            Messages
          </a>
          <div className={btnclassesM.join(' ')}>
            <a href="">New</a>
            <a href="">Sent</a>
          </div>
        </li>
        <li className="item" id="logout">
          <a className="btn" href="#">
            Logout
          </a>
        </li>
      </div>
    </div>
  );
};

export default AccordioMenu;

标签: reactjs

解决方案


如果您想进一步简化这一点,您可以只使用单态值,这样组件就可以共享一个单一的事实来源。

让我们有一个存储标识符数组的状态。每个标识符都与一组不同的链接相关联。我们将使用“message”和“profile”作为标识符。自然,如果数组中没有任何内容,则所有子链接都应该折叠。

然后我们可以只使用一个事件处理程序将标识符添加/删除到state数组中。最后,我们可以使用内联样式来确定与标识符对应的链接集是否应该包含open该类。

import React, { useState } from "react";

const AccordioMenu = () => {
  const [ selectedItems, setSelectedItems ] = useState([])

  //event-handler accepts an identifer-string as an argument
  const handleSelect = (identifier) => {
     //creates a copy of the original state to avoid state-mutation
     const selectedItemsCopy = [...selectedItems]

     //check if the idenifier that was passed already exists in the state
     if(selectedItemsCopy.includes(identifier)){
         //it already exists, which means the menu-links are expanded
         const foundIndex = selectedItemsCopy.indexOf(identifier)
         //you've clicked it to hide it. so remove the identifier from the state
         selectedItemsCopy.splice(foundIndex, 1)
         setSelectedItems(selectedItemsCopy)
     } else {
        //if identifier was not found in state. then add it.
        setSelectedItems([...selectedItems, identifier])
     }
  }

  return (
    <div className="middle">
      <div className="menu">
        <li className="item" id="profile">
          //set up handler to pass identifier
          <a className='btn' href="#" onClick={() => handleSelect("profile")}>
            Profile
          </a>
          <div className={selectedItems.includes("profile") ? "smenu open" : "smenu"}>
            <a href="">Posts</a>
            <a href="">Pictures</a>
          </div>
        </li>
        <li className="item" id="messages">
          //set up handler to pass identifier
          <a className="btn" href="#" onClick={() => handleSelect("message")}>
            Messages
          </a>
          <div className={selectedItems.includes("messages") ? "smenu open" : "smenu"}>
            <a href="">New</a>
            <a href="">Sent</a>
          </div>
        </li>
        <li className="item" id="logout">
          <a className="btn" href="#">
            Logout
          </a>
        </li>
      </div>
    </div>
  );
};

export default AccordioMenu;

推荐阅读