Reputation: 1021
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:
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
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
Reputation: 24915
You should use boolean value as an accordion can have 2 values.
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.
const [toggleValue, setToggleValue] = useState(false);
const toggleHandler = () => {
setToggleValue(!toggleValue);
};
const AccordionView = ({ accordionData }) => {
return (
<div>
{accordionData.map((item) => (
<NormalAccordion content={item.content} />
))}
</div>
);
};
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"
}
];
index.js
import { accordionData } from '../constants/accordion-data'
...
<NormalAccordion accordionData={ accordionData } />
Upvotes: 1