javascript - How to open the accordion for each item when click on icon? - Stack Overflow

I have created an accordion type ponent in reactjs In this When I open the first toggle, only toggle on

I have created an accordion type ponent in reactjs In this When I open the first toggle, only toggle one content should open, when clicked on second toggle then the toggle one content should close and only toggle second content should be open(Only one toggle should be open at a time) . But in my case everytime same div is getting open. I don't know where I did wrong? and how to solve it?. below is my code

import React, { useState } from "react";
import { FaPlus, FaMinus } from "react-icons/fa";
import "./FAQ.scss";
import { Collapse } from "reactstrap";

const Question = (props) => {
    const [isOpen, setIsOpen] = useState(false);

    const toggle = () => setIsOpen(!isOpen);

    return (
        <div className="question">
            <div>
                <button onClick={toggle}>
                    {isOpen ? <FaMinus /> : <FaPlus />}
                </button>
            </div>
            <div onClick={toggle} className='title'>
                {props.question}
            </div>
                <Collapse isOpen={isOpen} className='content'>
                    The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for 
                    those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" 
                    by Cicero are also reproduced in their exact original form, acpanied by English 
                    versions from the 1914 translation by H. Rackham.
                </Collapse>
            <hr />
        </div>
    );
};

function FAQ() {
    return (
        <div className="faq" id='faq'>
            <h2>F.A.Q.</h2>
            <div className="faq-section">
                <Question question="Question one" />
                <Question question="Question two" />
                <Question question="Question three" />
                <Question question="Question four" />
                <Question question="Question five" />
            </div>
        </div>
    );
}

export default FAQ;

The screenshot is given in the below

UPDATE THE QUESTION

Below is the link of a website the have the FAQ section in the bottom, I am trying to make the toggle feature as they have. FAQ section in the bottom of this website

I have created an accordion type ponent in reactjs In this When I open the first toggle, only toggle one content should open, when clicked on second toggle then the toggle one content should close and only toggle second content should be open(Only one toggle should be open at a time) . But in my case everytime same div is getting open. I don't know where I did wrong? and how to solve it?. below is my code

import React, { useState } from "react";
import { FaPlus, FaMinus } from "react-icons/fa";
import "./FAQ.scss";
import { Collapse } from "reactstrap";

const Question = (props) => {
    const [isOpen, setIsOpen] = useState(false);

    const toggle = () => setIsOpen(!isOpen);

    return (
        <div className="question">
            <div>
                <button onClick={toggle}>
                    {isOpen ? <FaMinus /> : <FaPlus />}
                </button>
            </div>
            <div onClick={toggle} className='title'>
                {props.question}
            </div>
                <Collapse isOpen={isOpen} className='content'>
                    The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for 
                    those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" 
                    by Cicero are also reproduced in their exact original form, acpanied by English 
                    versions from the 1914 translation by H. Rackham.
                </Collapse>
            <hr />
        </div>
    );
};

function FAQ() {
    return (
        <div className="faq" id='faq'>
            <h2>F.A.Q.</h2>
            <div className="faq-section">
                <Question question="Question one" />
                <Question question="Question two" />
                <Question question="Question three" />
                <Question question="Question four" />
                <Question question="Question five" />
            </div>
        </div>
    );
}

export default FAQ;

The screenshot is given in the below

UPDATE THE QUESTION

Below is the link of a website the have the FAQ section in the bottom, I am trying to make the toggle feature as they have. FAQ section in the bottom of this website

Share Improve this question edited Aug 31, 2021 at 9:04 Inception_K asked Aug 31, 2021 at 8:10 Inception_KInception_K 1451 silver badge9 bronze badges 4
  • Each question appears to have its own isOpen state, so they should all be independent from one another. I don't see how it's possible for one to toggle all the others. – Drew Reese Commented Aug 31, 2021 at 8:13
  • @DrewReese I am trying to open div one when I clicked on toggle first same for others also – Inception_K Commented Aug 31, 2021 at 8:16
  • 1 But in my case everytime same div is getting open, or open div one when I clicked on toggle first same for others also . it is not clear what you want to do – Amir-Mousavi Commented Aug 31, 2021 at 8:18
  • @Amir-Mousavi I want to if I clicked on first toggle- first div, second toggle- second div, means I want to open different div on different toggle. in my case everytime same div is getting open – Inception_K Commented Aug 31, 2021 at 8:24
Add a ment  | 

2 Answers 2

Reset to default 3

Issue

The issue here is that all Question ponents have their own state, independent of the others.

Solution

If you want to only open one Question at-a-time then the state needs to be lifted and declared in FAQ. This is so there's a single source of truth for what is opened/expanded.

FAQ

Move the isOpen state and toggle handler to this parent ponent. Use an "id" to toggle on/off the question ponent you want to expand. Pass an isOpen and toggle props to each Question ponent and handle the id logic here.

function FAQ() {
  const [isOpen, setIsOpen] = useState(null);

  const toggleOpen = id => () => setIsOpen(
    isOpen => isOpen === id ? null : id,
  );

  return (
    <div className="faq" id='faq'>
      <h2>F.A.Q.</h2>
      <div className="faq-section">
        <Question
          question="Question one"
          isOpen={isOpen === 0}
          toggle={toggleOpen(0)}
        />
        <Question
          question="Question two"
          isOpen={isOpen === 1}
          toggle={toggleOpen(1)}
        />
        <Question
          question="Question three"
          isOpen={isOpen === 2}
          toggle={toggleOpen(2)}
        />
        <Question
          question="Question four"
          isOpen={isOpen === 3}
          toggle={toggleOpen(3)}
        />
        <Question
          question="Question five"
          isOpen={isOpen === 4}
          toggle={toggleOpen(4)}
        />
      </div>
    </div>
  );
}

Question

Call/consume the isOpen and toggle from the passed props.

const Question = (props) => {
  return (
    <div className="question">
      <div>
        <button onClick={props.toggle}>
          {props.isOpen ? <FaMinus /> : <FaPlus />}
        </button>
      </div>
      <div onClick={props.toggle} className='title'>
        {props.question}
      </div>
      <Collapse isOpen={props.isOpen} className='content'>
        ....
      </Collapse>
      <hr />
    </div>
  );
};

Update

Ok, since it seems you are struggling with the issue of rendering the same "content" in each Question ponent I suggest you load up all your questions and content into an array and map them instead of hardcoding the JSX.

FAQ

const faqData = [
  {
    question: "Question one",
    content: <div> .... I'm content .... </div>, // <-- anything renderable as a child
  },
  ... etc...
];

function FAQ() {
  const [isOpen, setIsOpen] = useState(null);

  const toggleOpen = id => () => setIsOpen(
    isOpen => isOpen === id ? null : id,
  );

  return (
    <div className="faq" id='faq'>
      <h2>F.A.Q.</h2>
      <div className="faq-section">
        {faqData.map(({ content, question}, index) => (
          <Question
            key={index}
            content={content}
            question={question}
            isOpen={isOpen === index}
            toggle={toggleOpen(index)}
          />
        ))}
      </div>
    </div>
  );
}

Question

const Question = ({ content, question, isOpen, toggle }) => {
  return (
    <div className="question">
      <div>
        <button onClick={toggle}>
          {isOpen ? <FaMinus /> : <FaPlus />}
        </button>
      </div>
      <div onClick={toggle} className='title'>
        {question}
      </div>
      <Collapse isOpen={isOpen} className='content'>
        {content}
      </Collapse>
      <hr />
    </div>
  );
};

And just in case you missed it, you also need to import the bootstrap CSS somewhere in your project to get the bootstrap styles, transitions, and animations working.

import "bootstrap/dist/css/bootstrap.min.css";

You can do by move isOpen to the FAQ ponent and using map to return questions

in the FAQ:

const [open, setOpen] = useState(null);

const onClick = (i) => {
  setOpen(open === i ? null : i);
};

{
  questions.map((question, i) => (
    <Question key={i} question={question} isOpen={open === i} toggle={() => onClick(i)} />
  ));
}

in the Question

const Question = ({isOpen, toggle, question}) => {
  ...
  <button onClick={props.toggle}>
     {isOpen ? <FaMinus /> : <FaPlus />}
  </button>
  ...
  <div onClick={toggle} className="title">
    {question}
  </div>
  ...
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745036242a4607535.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信