When one is clicked, the others should not expand.
Below is my current code, I have tried to create a separate isOpen state value, but I Ended up messing it even more. Below is the code that you see on the screen-shot.
This first part of the code is the Accordion Item
import { memo, useState } from "react";
import styles from "./AccordionItemFAQ.module.scss";
interface AccordionItemFAQProps {
title: string;
content: string;
}
const AccordionItemFAQ: React.FC<AccordionItemFAQProps> = ({ title, content }) => {
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
setIsOpen(!isOpen);
};
return (
<div className={styles.containerAll}>
<button onClick={handleClick} className={styles.containerTitle}>
{title}
</button>
{isOpen && (
<div className={styles.containerContent}>
<div className={styles.splitter}></div>
<div className={styles.content}>{content}</div>
</div>
)}
</div>
);
};
export default memo(AccordionItemFAQ);
Below is the FAQ page code, where i import the Accordion Item to the main page
import styles from "styles/pages/FAQ.module.scss";
import type { LayoutProps } from "@root/layouts";
import { buildMainLayout } from "@root/layouts";
import { useEffect, useState } from "react";
import { FaqTable } from "@root/constants/types";
import axios from "axios";
import AccordionItemFAQ from "@root/components/AccordionItemFAQ";
export default function Faq() {
const [faqTable, setFaqTable] = useState<FaqTable[]>([]);
const api = "http://localhost:8088/api/v1/faq";
const loadFaqTable = () => {
axios.get(api).then((response) => setFaqTable(response.data));
};
useEffect(() => {
loadFaqTable();
}, []);
return (
<div>
<h1>FAQ</h1>
<div className={styles.parentContainer}>
{faqTable.map((item) => (
<AccordionItemFAQ key={item.faqId} title={item.question} content={item.answer}></AccordionItemFAQ>
))}
</div>
</div>
);
}
// <-- layout
const layoutProps: LayoutProps = {
mainClassName: "faq",
currentPageDescription: "faqPage",
};
Faq.layout = buildMainLayout(layoutProps);
2
Answers
I would control the open/close state and click handler from the parent Faq component. You can pass the id of the selected faq to the click handler to keep track of which faq should be opened. If unselecting (all faqs closed) is needed, you can set the selected state back to null.
in these cases where you essentially want to determine behaviour based on siblings its probably easiest to delegate the coordination of events, and therefore also state, back up to the parent. So in this case you should handle state and callback determination on the FAQ page component.
You can add something similar to
on the page component, where
Id
represents whatever datatype you can use as an id that is present on each faq item.Then you should extend the props for the individual FAQ item to accept a callback that determines the expected behaviour for when the target is clicked. You will also need to add a prop that represents whether the accordion is open, this is essentially propagating the parent state back down to the individual item.
This would look something like this
Then update the FAQ component to use these props
Then finally you can pass the props to the new ItemFaq component
However you design the callback depends on different factors so there’s room for improvement or just changing things. You can change it to only call setState if current state undefined, you can also define it in the page component if you dont like inline functions.
Eventually you probably also want to change the callback to set the state to undefined if called on the same id that is currently active. Maybe like this
Hope it helps as a starting point,
Best