Undefined
Undefined

Reputation: 1021

React - How to change the text of accordion heading of the current clicked item

I am making a simple Reactjs accordion application in which collapse and expanding of each individual items are done.

Requirement:

A simple requirement is that I am in the need to toggle the text of the heading as Expand or Shrink based on the click.

If we click any of the item then the content will gets displayed in that case the text changes to Shrink as because the accordion gets opened so the Shrink title is given for closing of the accordion.

Complete working example:

https://codesandbox.io/s/react-accordion-forked-lcyr0

In the above example I have used the following code to change the text,

Accordion.js

import React, { useState } from "react";
import Text from "./text";
import Heading from "./heading";
import getAccordion from "./GetAccordion";

const Accordion = getAccordion(1);

const accordionData = [
  {
    id: 1,
    content: "This is a first content"
  },
  {
    id: 2,
    content: "This is a second content"
  },
  {
    id: 3,
    content: "This is a third content"
  }
];

const NormalAccordion = () => {
  const [toggleValue, setToggleValue] = useState(-1);

  const toggleHandler = (index) => {
    setToggleValue(index);
  };

  return (
    <div>
      {accordionData.map((item, index) => (
        <Accordion>
          <Heading>
            <div
              style={{ padding: "10px", cursor: "pointer" }}
              className="heading"
              onClick={() => toggleHandler(index)}
            >
              {toggleValue !== index ? `Expand` : `Shrink`}
            </div>
          </Heading>
          <Text>{item.content}</Text>
        </Accordion>
      ))}
    </div>
  );
};

export default NormalAccordion;

And this line {toggleValue !== index ? `Expand` : `Shrink`} changes the text once but after that it doesn't make any changes on further toggle over the title(Expand/Shrink).

Kindly help me to achieve the result of toggling the text between Expand and Shrink based on the respective clicks.

Upvotes: 2

Views: 2809

Answers (2)

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You should reset the toggleValue if the item is already clicked :

  const toggleHandler = (index) => {

    index===toggleValue?setToggleValue(-1): setToggleValue(index);
  };

then use condition to render the current content:

<Text>{toggleValue === index && item.content}</Text>

and simplify the Text component to this one :

<div style={{ ...this.props.style }}>
        <div className={`content ${this.props.text ? "open" : ""}`}>
          {this.props.children}
        </div>
      </div>

Upvotes: 1

Rajesh
Rajesh

Reputation: 24915

You should use boolean value as an accordion can have 2 values.

Idea:

  • Create a standalone accourdion component which defines a behavior of expand/ collapse.
  • Create a wrapper view component that calls this this component.
  • Pass your data as a prop from this view instead of using a local hard coded object.

Benefit of this approach is that you have 2 modular components that work only on props. These can be exported later to their own standalone library.

Ideally, a component should be dumb and should only know its own behavior based on state and props.

Updated sandbox

  • Accoirdion component changes
const [toggleValue, setToggleValue] = useState(false);

const toggleHandler = () => {
  setToggleValue(!toggleValue);
};
  • Accordion view changes
const AccordionView = ({ accordionData }) => {
  return (
    <div>
      {accordionData.map((item) => (
        <NormalAccordion content={item.content} />
      ))}
    </div>
  );
};
  • Constants: I create a folder called constants that will hold hardcoded objects and then we pass it using props from index.js
export const accordionData = [{
    id: 1,
    content: "This is a first content"
  },
  {
    id: 2,
    content: "This is a second content"
  },
  {
    id: 3,
    content: "This is a third content"
  }
];
  • Changes in index.js
import { accordionData } from '../constants/accordion-data'

...

<NormalAccordion accordionData={ accordionData } />

Upvotes: 1

Related Questions