【问题标题】:How can I unset an active class on each child component while setting it to active for the clicked child如何在每个子组件上取消设置活动类,同时为单击的子组件设置为活动类
【发布时间】:2019-05-02 15:06:02
【问题描述】:

我试图在子组件 B 上设置一个活动类,同时在我单击 B 时禁用子组件 A 上的活动类。

到目前为止,我已经尝试在父类中使用钩子,通过使用setActive(''); 取消设置所有子类的活动道具,然后使用e.currentTarget.className === 'link--active' ? e.currentTarget.className = '' : e.currentTarget.className = 'link--active'; 将当前目标的类设置为链接-活动。可悲的是,此时它所做的只是在点击的孩子上添加类或删除类。

家长:

  const [active, setActive] = useState('');

  const navigate = (e) => {
    setActive('');
    e.currentTarget.className === 'link--active' ? e.currentTarget.className = '' : e.currentTarget.className = 'link--active';
  };

在return语句中:

{menuItems.map((item, index) => (
  <li key={index} >
    <NavLink target={item} onClick={(e) => navigate(e)} active={active} />
  </li>
))}

孩子们:

<a href="#"
   onClick={props.onClick} 
   className={props.active}>
   {props.target}
</a>

编辑:

使用 Ori Drori 的解决方案后,活动类设置在单击的 NavLink 上并从其余部分中删除。由于我希望 onClick 成为导航功能,因此我所做的只是将父级中的 onClick 设置为导航,并通过使用 id 作为参数来调用 setActive 并在导航函数中以 id 作为参数再次调用 setActive。这些类现在看起来像这样:

家长:

const [active, setActive] = useState(null);

const navigate = (id) => {
  setActive(id);
};

return (
    {menuItems.map((item) => (
      <li key={item.id} >
        <NavLink 
          {...item}
          isActive={active === item.id}
          onClick={navigate} />
      </li>
    ))}
)

孩子:

const NavLink = ({id, target, isActive, onClick}) => {
  return (
      <a href="#"
        onClick={useCallback(() => onClick(id), [id, onClick])} 
        className={isActive ? 'active' : ''}>
        {target}
      </a>
  );
}

【问题讨论】:

    标签: reactjs parent-child react-hooks setstate


    【解决方案1】:

    setActive 传递给导航链接。当单击NavLink 时,它将通过setActive 设置为id。每个项目还接收isActive 属性,如果active 状态匹配它的id,则为true

    const { useCallback, useState } = React
    
    const NavLink = ({ id, target, isActive, onClick }) => (
      <a href="#"
         onClick={useCallback(() => onClick(id), [id])} 
         className={`navLink ${isActive ? 'active' : ''}` }>
         {target}
      </a>
    )
    
    const Parent = ({ menuItems }) => {
      const [active, setActive] = useState(null);
    
      return (
        <ul>
          {menuItems.map((item) => (
            <li key={item.id} >
              <NavLink 
                {...item} 
                onClick={setActive} 
                isActive={active === item.id} />
            </li>
          ))}
        </ul>
      )
    }
    
    const items = [{ id: 0, target: 'Ready' }, { id: 1, target: 'Player' }, { id: 2, target: 'One' }]
    
    ReactDOM.render(
      <Parent menuItems={items} />,
      demo
    )
    .navLink {
      color: blue;
      text-decoration: none;
    }
    
    .active {
      color: red;
    }
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
    <div id="demo"></div>

    【讨论】:

    • 感谢您的回复,目前它确实有效,但是我遇到的下一个问题是每个 navlink 现在调用 setActive 而不是在其中调用 setActive 的导航。是否可以调用导航,而导航又会调用 setActive?
    • 没关系,我已经找到解决方案了,我会在编辑中发布它
    【解决方案2】:

    (1) Assign an id to each of child components
    (2)Add inactive class to all child components
    (3) Remove inactive class from selected component and add active class to it
    这是您问题的有效解决方案。希望对你有帮助。

    class App extends React.Component {
      state = {
        childComponents: [
          { id: "ironman", component: <IronMan /> },
          { id: "captainamerica", component: <CaptainAmerica /> },
          { id: "thor", component: <Thor /> },
          { id: "loki", component: <Loki /> },
          { id: "spiderman", component: <Spiderman /> }
        ],
        currComponentId: ""
      };
    
      clickHandler = idComponent => {
        // get access to all classes
        if (this.state.currComponentId !== "")
          document
            .getElementById(this.state.currComponentId)
            .classList.remove("active");
        let element = document.getElementsByClassName("child-components");
        for (let index = 0; index < element.length; index++) {
          element[index].classList.add("inactive");
        }
        document.getElementById(idComponent).classList.remove("inactive");
        document.getElementById(idComponent).classList.add("active");
        this.setState({ currComponentId: idComponent });
      };
      render() {
        return (
          <div className="parent">
            <ul>
              {this.state.childComponents.map(element => {
                return (
                  <li>
                    <button
                      id={element.id}
                      className="child-components"
                      onClick={() => this.clickHandler(element.id)}
                    >
                      {element.id}
                    </button>
                    {this.state.currComponentId === element.id ? (
                      <span> Active component</span>
                    ) : null}
                  </li>
                );
              })}
            </ul>
            <div>
              {this.state.childComponents.map(element => {
                if (element.id === this.state.currComponentId)
                  return <div>{element.component}</div>;
              })}
            </div>
          </div>
        );
      }
    }
    
    
    const IronMan = () => <div>This is IronMan Component</div>;
    const CaptainAmerica = () => <div>This is CaptainAmerica Component</div>;
    const Thor = () => <div>This is Thor Component</div>;
    const Loki = () => <div>This is Loki Component</div>;
    const Spiderman = () => <div>This is Spiderman Component</div>;
    
    ReactDOM.render(<App/>, document.getElementById('root'));
    .active {
      border: solid 1px red;
      background-color: black;
      color: #fff;
    }
    .inactive {
      color: #000;
      background-color: #fff;
    }
    .parent{
     border: solid 1px #322f31;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <div id='root' />

    【讨论】:

      【解决方案3】:

      我想我会在父节点中有一个状态条目,例如whichIsActive,并使用 onclick 函数为其设置一个活动链接的属性,例如索引。

      const navigate = (index) => {
      this.setState{(whichIsActive: index)}
       };
      

      然后在您的 className 中,您可以执行类似 className=${this.state.whichIsActive === index &amp;&amp; 'active'} 的操作(不要忘记周围的 `)。我没有测试过它,但我认为它应该可以工作。

      【讨论】:

        猜你喜欢
        • 2021-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-23
        • 2018-08-24
        • 2018-02-21
        • 2020-08-06
        • 1970-01-01
        相关资源
        最近更新 更多