How to track current accordion item using state in React?

Viewed 212

I am trying to change state (from "show" to "hide") only for current item.

const disputes = [
    { id: 111, statusId: 6, buyerId: 1151, productName: "apple" },
    { id: 222, statusId: 6, buyerId: 1151, productName: "pear" },
    { id: 33, statusId: 6, buyerId: 546, productName: "lemon" }
];

const [disputeHistoryShow, setDisputeHistoryShow] = useState(true)

const textChange = () => {
  setDisputeHistoryShow((prev) => !prev)
}

return (
  <Accordion>
    {disputes.map((dispute) => (
      <Card>
        <Card.Header>
          <Accordion.Toggle
            as={Button}
            variant="button"
            eventKey={dispute.id}
            onClick={textChange}
          >
            <div className="  row c">
              <div className=" font-weight-bold">dispute №</div>
              <div> {dispute.id}</div>
              <div>{disputeHistoryShow ? 'show' : 'hide'}</div>
            </div>
          </Accordion.Toggle>
        </Card.Header>
        <Accordion.Collapse eventKey={dispute.id}>
          <Card.Body>
            <div>{dispute.productName}</div>
          </Card.Body>
        </Accordion.Collapse>
      </Card>
    ))}
  </Accordion>
)

But when I am clicking to any item all other also changing their state from show to hide. How can I fix that problem?

Here is sandbox.

1 Answers

Issue:

You can not track the current active item using a single boolean state (what you currently have):

const [disputeHistoryShow, setDisputeHistoryShow] = useState(true);

Solution:

You need to store active item ID in the state, like:

const [activeId, setActiveId] = useState(null);

const textChange = (id) => {
  setActiveId(prev => prev === id ? null : id);
};

And then change your Accordion code to use the ID in state:

<Accordion.Toggle
  as={Button}
  variant="button"
  eventKey={dispute.id}
  onClick={() => textChange(dispute.id)}   // Here: Pass the ID on Click
>
  <div className="  row c">
    <div className=" font-weight-bold">dispute №</div>
    <div> {dispute.id}</div>
    <div>{activeId === dispute.id ? "show" : "hide"}</div>  // Here: Use the ID
  </div>
</Accordion.Toggle>
Related