Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

74
Views
FAQ's section individual toggle incorrectly opening all parts on click

I've been trying to do a sort of toggle whereby you are able to click on a question to expand the answer. I've tried adapting the code from https://codesandbox.io/s/polished-rain-xnez0?file=/src/App.js, which was from another question on here.

Instead of creating a map in the parent component and passing in them separately to a reusable 'Expandable' component to render separate functional components as shown in the example, I tried creating the map within the FAQ component:

FAQ Expandable Component:

const FAQ = ({ questions }) => {

const [expanded, setExpanded] = useState(false);

const handleClick = () => {
    setExpanded((prevExpanded) => !prevExpanded);
  };

const renderedQuestions = questions.map((question, index) => {

    return (
        <React.Fragment key={question.id}>
            <FAQIndividualWrapper>
                <FAQTitle 
                    className='title'
                    onClick={() => handleClick()}
                >
                    {/* <i></i> */}
                    {question.title}
                </FAQTitle>
                <FAQContent className='content' style={{ display: expanded ? "block" : "none" }}>
                    {question.content}
                </FAQContent>
            </FAQIndividualWrapper>
        </React.Fragment>
    )
})


return (
    <>
    {renderedQuestions}
    </>
)

Parent Component:

const questions = [
{
    id: 1,
    title: 'Question 1',
    content: 'Answer 1'
},
{
    id: 2,
    title: 'Question 2',
    content: 'Answer 2'
}
]

const FAQSection = () => {
    return (
        <FAQPageContainer>
            <FAQWrapper>
                <FAQ questions={questions} />
            </FAQWrapper>

        </FAQPageContainer>
    )
}

However, my code results in all the answers being expanded on any click of either question. Why is this happening?

Also, how should I structure and fix the code for 'ideal' programming?

Thank you!

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

The problem with your code is that you only have one expanded state for all questions. This means the open/collapse state is the same for all questions.

If you want to include all of your code inside one component. You need to somehow distinguish the open/collapse state of each child.

Here I'm using an array to store individual open/collapse state of each child.

  // initial state is an array with the length of your questions array, default to false
  const [expandedIndexes, setExpandedIndexes] = useState(
    Array(info.length).fill(false)
  );
 
  const handleClick = (index) => {
    setExpandedIndexes((prevExpandedIndexes) => {
      const newState = [...prevExpandedIndexes];
      // set state for the corresponding index
      newState.splice(index, 1, !prevExpandedIndexes[index]);
      return newState;
    });
  };
  return (
    <div className="details">
      {info.map(({ title, details, id }, index) => (
        <div key={id} className="details-wrapper">
          <div>
            <h3 className="title">{title}</h3>
            <button onClick={() => handleClick(index)}>+</button>
          </div>
          <p
            className="text"
            // check the corresponding state to display
            style={{ display: expandedIndexes[index] ? "block" : "none" }}
          >
            {details}
          </p>
        </div>
      ))}
    </div>
  );

Codesandbox

Also, how should I structure and fix the code for 'ideal' programming?

Ideally, you want to follow the convention in your codesandbox link above. That way you don't need to deal with this kind of logic, each child will have its own state/handleClick function.

about 4 years ago · Juan Pablo Isaza Report

0

It is correct that the issue is caused by the fact that you've only a single boolean state.

Use an object to store the ids of the questions that are expanded, toggling a boolean value for each.

Example:

const FAQ = ({ questions }) => {
  const [expanded, setExpanded] = useState({});

  // Curried callback to enclose the id in callback scope
  const handleClick = id => () => {
    setExpanded(expanded => ({
      ...expanded,
      [id]: !expanded[id],
    }));
  };

  return questions.map((question) => (
    <FAQIndividualWrapper key={question.id}>
      <FAQTitle
        className='title'
        onClick={handleClick(question.id)}
      >
        {question.title}
      </FAQTitle>
      <FAQContent
        className='content'
        style={{ display: expanded[question.id] ? "block" : "none" }}
      >
        {question.content}
      </FAQContent>
    </FAQIndividualWrapper>
  ));
}
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!