代码之家  ›  专栏  ›  技术社区  ›  ollylove

如何将`$(this).toggleClass()`从jQuery转换为React

  •  -1
  • ollylove  · 技术社区  · 10 月前

    我刚开始学习React,我正在用Next.js构建一个网站,我只掌握了基础知识。
    我是一名网页设计师和CSS开发人员,我已经使用jQuery 10年了,主要用于在点击、悬停等操作中切换元素上的类。现在我想在React中做同样的事情,但它不像jQuery那么简单,我只是无法理解它,因为它对我来说有点太合乎逻辑了。
    以下是一个示例:一次只打开一个手风琴面板:

    $(".panel").on("click", function() {
      $(".panel").not($(this)).removeClass("open")
      $(this).toggleClass("open")
    })
    .accordion {
      max-width: 300px;
      padding: 20px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      font-family: Arial, sans-serif;
    }
    
    .panel {
      width: 100%;
      border: 1px solid black;
      cursor: pointer;
      margin-bottom: 10px;
    }
    
    .panel h6 {
      font-size: 14px;
      margin: 0;
      padding: 10px;
      background: wheat;
    }
    
    .panel p {
      font-size: 0;
      padding: 0 10px;
      margin: 0;
      transition: all 0.3s linear;
    }
    
    .panel.open p {
      font-size: 14px;
      padding: 10px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    
    <div class="accordion">
      <div class="panel">
        <h6>Panel One</h6>
        <p>Lorem ipsum dolor sit amet</p>
      </div>
      <div class="panel">
        <h6>Panel Two</h6>
        <p>Lorem ipsum dolor sit amet</p>
      </div>
      <div class="panel">
        <h6>Panel Three</h6>
        <p>Lorem ipsum dolor sit amet</p>
      </div>
    </div>

    只需3行JS,工作完成。现在我想在React中做同样的事情,但不知道该怎么做。我的尝试:

    import { useState } from "react"
    
    export default function Accordion() {
        const [isActive, setIsActive] = useState(false)
        let classNames = 'panel ' + (isActive ? 'active' : '')
    
        function handleClick() {
            setIsActive(!isActive)
        }
        
        return (
            <div className="accordion">
                <Panel className={classNames} onClick={handleClick}>
                    <h6>Panel One</h6>
                    <p>Lorem Ipsum Dolor Sit Amet</p>
                </Panel>
                <Panel className={classNames} onClick={handleClick}>
                    <h6>Panel Two</h6>
                    <p>Lorem Ipsum Dolor Sit Amet</p>
                </Panel>
                <Panel className={classNames} onClick={handleClick}>
                    <h6>Panel Three</h6>
                    <p>Lorem Ipsum Dolor Sit Amet</p>
                </Panel>
            </div>
        )
    }
    
    function Panel({ children, className, onClick }) {
        return (
            <div className={className} onClick={onClick}>
                {children}
            </div>
        )
    }
    

    但它效果不佳,当我点击一个面板时,所有面板都会一起打开/关闭。
    所有在线教程均可使用 .map() ,但理想情况下,我想避免它。
    我明白在React中 useState 触发重新渲染,但是 useRef() 没有,所以我想我可以把它们结合起来,但话说回来,这不是我能做到的 panel.current.toggleClass('open') ,所以我不知道。

    TLDR:有人能帮我理解React的基础知识吗,特别是如何在点击时“翻译”jQuery函数 $(element).not($(this)).removeClass(class); $(this).toggleClass(class) ?

    1 回复  |  直到 10 月前
        1
  •  0
  •   Arkellys    10 月前

    既然你的要求是控制每一个 Panel 单独地,然后一次只能打开其中一个(根据您的示例),那么您的状态必须存储打开的面板,而不是布尔值。既然你不想用 map ,为了避免更多的重复,您应该考虑移动 classNames 进入 面板 组件。

    export default function Accordion() {
      const [activePanel, setActivePanel] = useState(null);
    
      const handleClick = (panelId) => {
        setActivePanel((prevActivePanel) => (
          prevActivePanel === panelId ? null : panelId
        ));
      };
     
      return (
        <div className="accordion">
          <Panel
            isActive={activePanel === 1}
            onClick={() => handleCLick(1)}
          >
            <h6>Panel One</h6>
            <p>Lorem Ipsum Dolor Sit Amet</p>
          </Panel>
    
          <Panel
            isActive={activePanel === 2}
            onClick={() => handleClick(2)}
          >
            <h6>Panel Two</h6>
            <p>Lorem Ipsum Dolor Sit Amet</p>
          </Panel>
    
           <Panel
             isActive={activePanel === 3}
             onClick={() => handleClick(3)}
           >
             <h6>Panel Three</h6>
             <p>Lorem Ipsum Dolor Sit Amet</p>
           </Panel>
        </div>
      );
    }
    
    function Panel({ children, isActive, onClick }) {
      const classNames = 'panel ' + (isActive ? 'active' : '');
    
      return (
        <div className={className} onClick={onClick}>
          {children}
        </div>
      );
    }