React:如何打开新添加的手风琴项?

Posted

技术标签:

【中文标题】React:如何打开新添加的手风琴项?【英文标题】:React: How to open a newly added accordion item? 【发布时间】:2021-12-16 10:46:59 【问题描述】:

我的 React 应用程序中有一个手风琴组件。用户可以向这个手风琴添加项目。现在,当用户单击按钮将项目添加到手风琴时,我希望新添加的手风琴项目自动打开。这是codesandbox displaying my problem。

为了打开和关闭手风琴,我使用了一些状态:const [clicked, setClicked] = useState("0");

当点击accordionItem 时,会调用以下函数:

  const handleToggle = (index) => 
    if (clicked === index) 
      return setClicked("0");
    
    setClicked(index);
  ;

在我的代码沙盒演示中,我使用了一系列问题和答案作为accordionItems,并循环遍历它们。所以我认为我所要做的就是使用setClicked 函数将clicked 状态设置为等于faqs 数组的长度减1,以便打开正确的手风琴,但这并不像预期的那样工作。 ..

参考代码

Accordion.jsx:

import AccordionItem from "./AccordionItem";
import  useState  from "react";

export default function Accordion() 
  const initialFaqs = [
    
      question: "Lorem ipsum dolor sit amet?",
      answer:
        "Tenetur ullam rerum ad iusto possimus sequi mollitia dolore sunt quam praesentium. Tenetur ullam rerum ad iusto possimus sequi mollitia dolore sunt quam praesentium.Tenetur ullam rerum ad iusto possimus sequi mollitia dolore sunt quam praesentium."
    ,
    
      question: "Dignissimos sequi architecto?",
      answer:
        "Aperiam ab atque incidunt dolores ullam est, earum ipsa recusandae velit cumque. Aperiam ab atque incidunt dolores ullam est, earum ipsa recusandae velit cumque."
    ,
    
      question: "Voluptas praesentium facere?",
      answer:
        "Blanditiis aliquid adipisci quisquam reiciendis voluptates itaque."
    
  ];

  const [faqs, setFaqs] = useState(initialFaqs);

  const [clicked, setClicked] = useState("0");

  const handleToggle = (index) => 
    if (clicked === index) 
      return setClicked("0");
    
    setClicked(index);
  ;

  const addFaq = () => 
    let newFaq = [...faqs];
    newFaq.push(
      question: "This accordion item should automatically open",
      answer:
        "Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur."
    );
    setFaqs(newFaq);

    //I want to open the accordion of the item that is just openend.
    //Currently, setting the clicked state equal to the length of the faqs gives an error.
    //Setting clicked equal to faqs.length - 1 does not open the newly added faq...
    //How to solve?
    setClicked(faqs.length);
  ;

  return (
    <div>
      <ul className="accordion">
        faqs.map((faq, index) => (
          <AccordionItem
            onToggle=() => handleToggle(index)
            active=clicked === index
            key=index
            faq=faq
          />
        ))
      </ul>
      <button onClick=() => addFaq() className="add-faq-btn">
        Add question
      </button>
    </div>
  );

AccordionItem.jsx:

import  useRef  from "react";

export default function AccordionItem( faq, active, onToggle ) 
  const contentEl = useRef();

  const  question, answer  = faq;
  return (
    <li className=`accordion_item $active ? "active" : ""`>
      <button className="button" onClick=onToggle>
        question
        <span className="control">active ? "—" : "+" </span>
      </button>
      <div
        ref=contentEl
        className="answer_wrapper"
        style=
          active
            ?  height: contentEl.current.scrollHeight 
            :  height: "0px" 
        
      >
        <div className="answer">answer</div>
      </div>
    </li>
  );

【问题讨论】:

你能在这里添加完整的react组件,以便我们可以看到完整的场景! @SahidHossen 我添加了它们。 【参考方案1】:

你的问题很少。

一个是你必须在添加过程中使用下面的newFaq(因为状态变量不会立即更新):

setClicked(newFaq.length - 1);

修复后你会得到另一个错误。那是因为您试图在 style 对象中渲染期间访问 DOM 元素的 ref:由于组件尚未放置在 DOM 上,ref 为空。您将需要这样的东西:

  React.useEffect(() => 
    setHeight(contentEl.current.scrollHeight);
  , []);

注意:老实说,我不确定上面的 useEffect 哪个是正确的依赖项,如果我们这样使用它,它将始终使用初始高度。如果某些项目的高度之后没有变化,这可以。

并在样式中使用height

style=active ?  height  :  height: "0px" 

【讨论】:

好吧,clicked === index 当点击当前打开的手风琴时,这又会关闭AccordionItem @Reinier68 在if 中添加一个console.log 看看它永远不会运行 if (clicked === index) console.log("clicked"); return setClicked("0"); 每次点击当前打开的手风琴项时,都会记录“点击”。单击相同手风琴项10次,您将看到5个控制台日志。 @Reinier68 啊是啊,就用setClicked(null),为什么setClicked("0") 没有具体原因:P,setClicked(null) 可能也可以正常工作,并且公平一点。这仍然没有解决原来的问题,呵呵。

以上是关于React:如何打开新添加的手风琴项?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据其唯一 ID 打开特定的嵌套引导手风琴

Javascript手风琴 - 折叠除活动之外的所有打开实例

如何使用 React Hooks 单独切换手风琴面板?

jQuery Accordion - 它会滚动到打开项目的顶部吗?

如何在 Outlook 2003/2007 的导航窗格(外观栏)中添加新按钮?

在新窗口中打开的反应导航栏菜单项