Khagesh Bansal
Khagesh Bansal

Reputation: 33

React Accordion opens and closes all elements

when I click on the button all accordion elements are opened. how to make only clicked element to be opened. this is a react accordion app. I am not able to find the problem in the code.

import React, { useState } from "react";
//import {questions} from './api';

const questions = [
  {
    id: 1,
    question: "what is a",
    answer: "a is a"
  },
  {
    id: 2,
    question: "what is b",
    answer: "b is b"
  },
  {
    id: 3,
    question: "what is c",
    answer: "c is c"
  }
];

function Accordian() {
  const [toggle, settoggle] = useState(false);

  function mapfunc(currentValue) {
    return (
      <div key={currentValue.id} className="elements">
        <h3 className="question">
          {currentValue.question}
          <button
            onClick={function () {
              settoggle(!toggle);
            }}
            className="button"
          >
            {toggle ? "➖" : "➕"}
          </button>
        </h3>

        {toggle && <p className="answer"> {currentValue.answer} </p>}
      </div>
    );
  }

  return (
    <div>
      <h1>Accordian App</h1>
      {questions.map(mapfunc)}
    </div>
  );
}

export default Accordian;

Upvotes: 0

Views: 408

Answers (2)

TheTisiboth
TheTisiboth

Reputation: 1651

The problem here, is that the state is at the Accordion level. So if it is true, all of the children of the Accordion will be opened. Instead, you should create a children component, that take as argument a question, and that has a local toggle state. You could instantiate it like this for instance:

return (
         <div>
            <h1>Accordian App</h1>
                {questions.map(question => <AccordionChildren question={question} />)}
        </div>
    )

Upvotes: 0

Amila Senadheera
Amila Senadheera

Reputation: 13265

You need to move the toggle item with its logic to a separate component.

Item

import React, { useState } from "react";

const Item = ({ currentValue }) => {
  const [toggle, settoggle] = useState(false);

  return (
    <div key={currentValue.id} className="elements">
      <h3 className="question">
        {currentValue.question}
        <button
          onClick={function () {
            settoggle(!toggle);
          }}
          className="button"
        >
          {toggle ? "➖" : "➕"}
        </button>
      </h3>

      {toggle && <p className="answer"> {currentValue.answer} </p>}
    </div>
  );
};

Accordian

const questions = [
  {
    id: 1,
    question: "what is a",
    answer: "a is a"
  },
  {
    id: 2,
    question: "what is b",
    answer: "b is b"
  },
  {
    id: 3,
    question: "what is c",
    answer: "c is c"
  }
];

function Accordian() {
  return (
    <div>
      <h1>Accordian App</h1>
      {questions.map((item) => (
        <Item currentValue={item} />
      ))}
    </div>
  );
}

export default Accordian;

Edit eloquent-feather-gesmy

Upvotes: 2

Related Questions