Problem Statement
Build an FAQ page where each question can be clicked to show or hide its answer.
Functional Requirements
- FAQ list: Render every item in
data.faqsunder the heading "Frequently Asked Questions". - Toggle: Clicking a question header shows its answer. Clicking it again hides it.
- Icon: The header shows "+" when closed and "−" when open.
- Independent items: Each item has its own
showstate, so several answers can be open at the same time.
Technical Constraints
- Read the questions and answers from a local
data.jsonfile. - Hide answers with the
showCSS class and amax-heighttransition instead of removing them from the DOM.
Code Flow
-
AccordionComponent:- The
Accordioncomponent takes aqnaprop (an object containingquestionandanswer) and renders a single accordion item. - It uses
useStateto manage the open/closed state (show) of the accordion. - When the accordion header is clicked, it toggles the
showstate, which controls the visibility of the content. - The icon changes dynamically between "+" (closed) and "−" (open) based on the
showstate. - Conditional classes are applied based on the
showstate to control visibility and behavior.
- The
-
FaqComponent:- The
Faqcomponent imports FAQ data from a JSON file. - It renders a container with a title "Frequently Asked Questions".
- It maps over the
faqsarray from the data and renders anAccordioncomponent for each FAQ item. - Each
Accordionreceives aqnaprop containing the question and answer.
- The
-
AppComponent:- The
Appcomponent is the root component that renders theFaqcomponent. - It serves as the entry point for the application.
- The
Key Concepts
1. useState Hook
- Purpose: The
useStatehook is used to manage component-level state in functional components. In this case, it tracks whether each accordion item is open or closed. - How it works:
useState(false)initializes theshowstate tofalse(accordion is closed by default).setShow(!show)toggles the state when the header is clicked.- The state change triggers a re-render, updating the UI to reflect the new state.
- State Management: Each
Accordioncomponent maintains its own independent state, allowing multiple accordions to be open simultaneously.
const [show, setShow] = useState(false);2. Conditional Rendering
- Purpose: Conditional rendering allows components to display different content based on state or props.
- How it works:
- The
showstate determines which content is displayed and which classes are applied. - The icon text changes based on the
showstate: "+" when closed, "−" when open. - The
accordion-contentdiv receives theshowclass conditionally, which controls its visibility. - Using template literals with ternary operators allows dynamic class names based on state.
- The
<span className="icon">{show ? "−" : "+"}</span>
<div className={`accordion-content ${show ? "show" : ""}`}>3. Event Handling
- Purpose: Event handlers allow components to respond to user interactions, such as clicks.
- How it works:
- The
onClickhandler is attached to theaccordion-headerbutton. - When clicked, it calls
setShow(!show)to toggle the state. - The
!showoperator inverts the current boolean value, effectively toggling betweentrueandfalse. - Arrow functions
() => setShow(!show)are used to create inline event handlers. - The state change triggers a re-render, updating the accordion's appearance and behavior.
- The
<button className="accordion-header" onClick={() => setShow(!show)}>4. Data Mapping
- Purpose: Mapping over arrays allows rendering multiple components dynamically from data.
- How it works:
- The
Faqcomponent imports FAQ data from a JSON file. - It uses the
.map()method to iterate over thefaqsarray. - For each FAQ item, it renders an
Accordioncomponent with the corresponding data. - The
keyprop is used to help React efficiently track and update list items during re-renders. - Using
indexas the key is acceptable here since the list is static and items don't reorder.
- The
{
data.faqs.map((faq, index) => <Accordion key={index} qna={faq} />);
}Code Breakdown
Accordion Component
import { useState } from "react";
const Accordion = ({ qna }) => {
const [show, setShow] = useState(false);
return (
<div className={`accordion ${show ? "active" : ""}`}>
<button className="accordion-header" onClick={() => setShow(!show)}>
<span className="question">{qna.question}</span>
<span className="icon">{show ? "−" : "+"}</span>
</button>
<div className={`accordion-content ${show ? "show" : ""}`}>
<p>{qna.answer}</p>
</div>
</div>
);
};
export default Accordion;- Props:
qna- An object containingquestionandanswerproperties. - State:
show- Boolean state that tracks whether the accordion is open or closed. - Logic:
- The component receives
qnaas a prop, which containsquestionandanswerproperties. useState(false)initializes the accordion in a closed state.- The
onClickhandler uses an arrow function to toggle the state:() => setShow(!show). - The ternary operator
show ? "−" : "+"conditionally renders the icon based on state. - Template literals with ternary operators create dynamic class names:
`${show ? "show" : ""}`.
- The component receives
- Rendering:
- The outer
divhas conditional classes based on theshowstate. - The
buttonelement serves as the clickable header with anonClickevent handler. - The
questionspan displays the FAQ question fromqna.question. - The
iconspan displays "+" or "−" based on the state using conditional rendering. - The
accordion-contentdiv conditionally receives theshowclass to control visibility. - The
ptag displays the FAQ answer fromqna.answer.
- The outer
Faq Component
import data from "../constants/data.json";
import Accordion from "./Accordian";
const Faq = () => {
return (
<div className="faq-container">
<h1>Frequently Asked Questions</h1>
<div className="faq-list">
{data.faqs.map((faq, index) => (
<Accordion key={index} qna={faq} />
))}
</div>
</div>
);
};
export default Faq;- Data Import: Imports FAQ data from a JSON file located in the constants folder using ES6 import syntax.
- Logic:
- Accesses the
faqsarray from the importeddataobject:data.faqs. - Uses the
.map()method to transform each FAQ object into anAccordioncomponent. - The map callback receives
faq(the current item) andindex(the array index). - Each
Accordionreceives aqnaprop containing thequestionandanswerproperties. - Uses
indexas thekeyprop to help React efficiently track list items during re-renders.
- Accesses the
- Rendering:
- Renders a container with a heading.
- Maps over the
faqsarray to render multipleAccordioncomponents dynamically. - Each
Accordionreceives aqnaprop with question and answer data.
App Component
import "./App.css";
import Faq from "./components/Faq";
function App() {
return (
<>
<Faq />
</>
);
}
export default App;- Purpose: Root component that renders the main
Faqcomponent. - Structure: Simple wrapper component that serves as the application entry point.
- Logic:
- Uses React Fragment (
<>...</>) to wrap theFaqcomponent without adding an extra DOM node. - Imports and renders the
Faqcomponent, which handles all the accordion logic.
- Uses React Fragment (
Data Structure (data.json)
{
"faqs": [
{
"question": "What is frontend development?",
"answer": "Frontend development refers to..."
},
...
]
}- Structure: JSON object containing an array of FAQ objects.
- Each FAQ Object:
question: String containing the FAQ question.answer: String containing the FAQ answer.
Summary
-
Code Flow:
- The
Appcomponent renders theFaqcomponent. - The
Faqcomponent imports FAQ data from a JSON file and maps over it to render multipleAccordioncomponents. - Each
Accordioncomponent manages its own open/closed state usinguseState(false). - Clicking the accordion header triggers the
onClickhandler, which callssetShow(!show)to toggle the state. - The state change triggers a re-render, updating the UI with conditional classes and content visibility.
- The icon and content visibility change based on the
showstate using conditional rendering.
- The
-
Key Takeaways:
useStatemanages component-level state for interactive UI elements.- Each accordion maintains independent state, allowing multiple items to be open simultaneously.
- Conditional rendering allows dynamic UI updates based on state (ternary operators, template literals).
- Event handlers (
onClick) enable user interaction and state updates. - Data mapping (
.map()) allows rendering multiple components dynamically from arrays. - The
keyprop helps React efficiently track and update list items during re-renders. - Template literals with ternary operators enable dynamic class names based on state.