Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

79
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda