如何在使用React JS中使用.map创建的元素列表中触发特定元素?

发布于 2025-02-11 20:30:16 字数 2130 浏览 1 评论 0原文

我正在尝试制作一部手风琴,该手风琴在单击“+”图标后打开。但是,当我单击一个元素时,所有其他元素都会扩展。有没有办法只打开其中一项手风琴?我添加了手风琴的屏幕截图,还添加了代码。

import { AiFillPlusCircle, AiFillMinusCircle } from "react-icons/ai";
import data from "../data";

export default function Container() {
  const [display, setDisplay] = useState(false);

  const clickHandle = () => {
    setDisplay(!display);
  };

  return (
    <>
      <div className="fContainer container">
        <div className="headingContainer">
          <h2 className="mainHeading">Questions And Answers About Login</h2>
        </div>

        <div className="fQuesContainer container">
          {data.map((question) => {
            const { id, title, info } = question;
            return (
              <div className="qCard" key={id}>
                <div className="qCardTitle">
                  <h4 className="qTitle">{title}</h4>
                  <button className="btnContainer" onClick={clickHandle}>
                    {display === false ? (
                      <AiFillPlusCircle size="2.4em" />
                    ) : (
                      <AiFillMinusCircle size="2.4em" />
                    )}
                  </button>
                </div>
                {/* This thing would return the info, or the element */}
                {display === false ? (
                  <></>
                ) : (
                  <>
                    <hr className="fHr" />
                    <p className="fInfo">{info}</p>
                  </>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}

“这是我单击

I'm trying to make an accordion, that opens up upon clicking the "+" icon. But when I click on a single element, all the other elements expand. Is there a way to just open one of the accordions? I've added the screenshot of the accordion and also added the code.

import { AiFillPlusCircle, AiFillMinusCircle } from "react-icons/ai";
import data from "../data";

export default function Container() {
  const [display, setDisplay] = useState(false);

  const clickHandle = () => {
    setDisplay(!display);
  };

  return (
    <>
      <div className="fContainer container">
        <div className="headingContainer">
          <h2 className="mainHeading">Questions And Answers About Login</h2>
        </div>

        <div className="fQuesContainer container">
          {data.map((question) => {
            const { id, title, info } = question;
            return (
              <div className="qCard" key={id}>
                <div className="qCardTitle">
                  <h4 className="qTitle">{title}</h4>
                  <button className="btnContainer" onClick={clickHandle}>
                    {display === false ? (
                      <AiFillPlusCircle size="2.4em" />
                    ) : (
                      <AiFillMinusCircle size="2.4em" />
                    )}
                  </button>
                </div>
                {/* This thing would return the info, or the element */}
                {display === false ? (
                  <></>
                ) : (
                  <>
                    <hr className="fHr" />
                    <p className="fInfo">{info}</p>
                  </>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}

This one is for the closed one

This one is after I click on the + icon.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏花。依旧 2025-02-18 20:30:16

说明

基本上,您不能使用单个变量来切换所有元素。所有元素都将充当一个元素,因此所有元素都将打开,或者全部都将关闭。

您需要可以对每个元素进行检查的东西。现在id是一个潜在的候选人,但它的缺点,因为它是列表的最佳选择是使用元素本身的索引。

因此,您首先将display从布尔值(false)键入integer键入键入-1(少于零),

然后更改您的.map来自.map((Question)=&gt; ... to .map(((问题,QuestionIndex)=&gt; ... <) /code>,这将为您提供一个变量QuestionIndex,该持有当前问题索引,

您可以使用该索引(QuestionIndex)和display> display> display变量to 互相检查并显示适当的状态,

与其他答案相比,

  1. 因为您正在处理项目列表,因此最好使用元素的索引来切换元素的显示将您的视图与您的数据脱钩(尽可能多)

  2. 如果出于某种原因,您的ID是无效的或重复的,它将在您的显示中创建问题。

  3. 只需调用toggleElement(2)即可自动通过代码(在第一次加载)为给定位置打开元素。如果要维护URL更改 /重新加载之间的开放状态,这很有用,只需将索引添加到URL的查询参数。< / p>。

解决方案

import { AiFillPlusCircle, AiFillMinusCircle } from "react-icons/ai";
import data from "../data";

export default function Container() {
  // Update the display to be of type integer and init it with -1
  const [display, setDisplay] = useState(-1);

  // Add a parameter to the click function to take the clicked element's index
  const toggleElement = (currentIndex) => {
    // Check if the element that is clicked is already open
    if(currentIndex===display) {
        setDisplay(-1); // If it is already open, close it.
    }
    else {
        setDisplay(currentIndex); // else open the clicked element
    }
  };

  return (
    <>
      <div className="fContainer container">
        <div className="headingContainer">
          <h2 className="mainHeading">Questions And Answers About Login</h2>
        </div>

        <div className="fQuesContainer container">
          {/* Add a variable questionIndex to the map method to get the index of the current question */}
          {data.map((question, questionIndex) => {
            const { id, title, info } = question;
            return (
              <div className="qCard" key={id}>
                <div className="qCardTitle">
                  <h4 className="qTitle">{title}</h4>
                  {/* Update the button onClick event to pass the current element's index via the questionIndex variable */}
                  <button className="btnContainer" onClick={()=> toggleElement(questionIndex)}>
                    {/* Update the UI state based on the comparison of the display and questionIndex variable  (Note, if they match, you need to open the element, else close) */}
                    {display == questionIndex ? (
                      <AiFillMinusCircle size="2.4em" />
                    ) : (
                      <AiFillPlusCircle size="2.4em" />
                    )}
                  </button>
                </div>
                {/* This thing would return the info, or the element */}
                {/* Update the UI state based on the comparison of the display and questionIndex variable  (Note, if they match, you need to open the element, else close) */}
                {display == questionIndex ? (
                  <>
                    <hr className="fHr" />
                    <p className="fInfo">{info}</p>
                  </>
                ) : (
                  <></>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}

Explanation

Basically you can't use a single variable to toggle all your elements. All the elements will act as a single element, so either all will open or all will close.

You need something that can be checked against each element. Now id is a potential candidate but it has it's drawbacks, since it's a list the best option is using the index of the element itself.

So you first change the display type from boolean (false) to integer type and default it to -1 (anything less than zero)

Then change your .map function from .map((question) =>... to .map((question, questionIndex) =>..., this will get you a variable questionIndex which holds the current question's index

You can use that (questionIndex) and the display variable to check against each other and display the appropriate states.

Benefits when compared to other answers

  1. Since you are dealing with a list of items, it is always best to use the index of an element to toggle the element's display, This ensures you have decoupled your View from your Data. (As much as possible)

  2. If for some reason your id is null or duplicate, it will create issues in your display.

  3. It is easier to just call toggleElement(2) to automatically open an element for a given position via code (on first load). This is useful if you want to maintain the open states between url changes / reloads, you just add the index to the query parameter of the url.

Solution

import { AiFillPlusCircle, AiFillMinusCircle } from "react-icons/ai";
import data from "../data";

export default function Container() {
  // Update the display to be of type integer and init it with -1
  const [display, setDisplay] = useState(-1);

  // Add a parameter to the click function to take the clicked element's index
  const toggleElement = (currentIndex) => {
    // Check if the element that is clicked is already open
    if(currentIndex===display) {
        setDisplay(-1); // If it is already open, close it.
    }
    else {
        setDisplay(currentIndex); // else open the clicked element
    }
  };

  return (
    <>
      <div className="fContainer container">
        <div className="headingContainer">
          <h2 className="mainHeading">Questions And Answers About Login</h2>
        </div>

        <div className="fQuesContainer container">
          {/* Add a variable questionIndex to the map method to get the index of the current question */}
          {data.map((question, questionIndex) => {
            const { id, title, info } = question;
            return (
              <div className="qCard" key={id}>
                <div className="qCardTitle">
                  <h4 className="qTitle">{title}</h4>
                  {/* Update the button onClick event to pass the current element's index via the questionIndex variable */}
                  <button className="btnContainer" onClick={()=> toggleElement(questionIndex)}>
                    {/* Update the UI state based on the comparison of the display and questionIndex variable  (Note, if they match, you need to open the element, else close) */}
                    {display == questionIndex ? (
                      <AiFillMinusCircle size="2.4em" />
                    ) : (
                      <AiFillPlusCircle size="2.4em" />
                    )}
                  </button>
                </div>
                {/* This thing would return the info, or the element */}
                {/* Update the UI state based on the comparison of the display and questionIndex variable  (Note, if they match, you need to open the element, else close) */}
                {display == questionIndex ? (
                  <>
                    <hr className="fHr" />
                    <p className="fInfo">{info}</p>
                  </>
                ) : (
                  <></>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}
缱绻入梦 2025-02-18 20:30:16

使用状态中的ID

  const [display, setDisplay] = useState("");

而不是布尔值,而是在映射项目时

  const { id, title, info } = question;
  const handleSetDisplay = () => {
     if(id === display) {
       //Close panel
       setDisplay("")
     } else {
       //open specific panel
       setDisplay(id)
     }
   }

,添加此功能调整按钮的ONCLICK

                  <button className="btnContainer" onClick={handleSetDisplay}>

,然后比较面板是否应该扩展,

 {display === id ? ///...: ...}

简而言之,您需要将保存的ID与映射的项目的ID进行比较。

如果您的ID是一个数字,只需将初始状态更改为0

Instead of a boolean, use an id in your state

  const [display, setDisplay] = useState("");

When you map an item, add this function

  const { id, title, info } = question;
  const handleSetDisplay = () => {
     if(id === display) {
       //Close panel
       setDisplay("")
     } else {
       //open specific panel
       setDisplay(id)
     }
   }

Adjust the button's onClick

                  <button className="btnContainer" onClick={handleSetDisplay}>

Then to compare if your panel should expand, use

 {display === id ? ///...: ...}

In short, you need to compare the saved ID with the mapped item's id.

If your id is a number, just change the initial state to 0

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文