He estado tratando de hacer una especie de alternar mediante el cual puede hacer clic en una pregunta para expandir la respuesta. Intenté adaptar el código de https://codesandbox.io/s/polished-rain-xnez0?file=/src/App.js , que era de otra pregunta aquí.
En lugar de crear un mapa en el componente principal y pasarlo por separado a un componente 'Expandible' reutilizable para generar componentes funcionales separados como se muestra en el ejemplo, intenté crear el mapa dentro del componente de preguntas frecuentes:
Componente ampliable de preguntas frecuentes:
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} </> )Componente principal:
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> ) }Sin embargo, mi código da como resultado que todas las respuestas se expandan con cualquier clic en cualquiera de las preguntas. ¿Por qué está pasando esto?
Además, ¿cómo debo estructurar y corregir el código para la programación 'ideal'?
¡Gracias!
El problema con su código es que solo tiene un estado expanded para todas las preguntas. Esto significa que el estado abierto/contraído es el mismo para todas las preguntas.
Si desea incluir todo su código dentro de un componente. Debe distinguir de alguna manera el estado abierto / colapsado de cada niño.
Aquí estoy usando una matriz para almacenar el estado individual de apertura/colapso de cada niño.
// 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> );Además, ¿cómo debo estructurar y corregir el código para la programación 'ideal'?
Idealmente, desea seguir la convención en su enlace de códigos y cuadro anterior. De esa manera, no necesita lidiar con este tipo de lógica, cada niño tendrá su propia función state/handleClick.
Es correcto que el problema se deba al hecho de que solo tiene un estado booleano.
Use un objeto para almacenar los id de las preguntas que se expanden, alternando un valor booleano para cada una.
Ejemplo:
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> )); }