There is a function called Question
that takes a list of objects (questionList
) and changes each object into a React component that shows a question and when clicked should reveal the answer in a FAQ style. There is another function called Answer
which shows the answer when a Question
container is clicked. However, instead of showing the answer of just the container which was clicked, it shows every answer of all the questions - as if rendered all the questions again with their answers. When a container is clicked again, all Answer
containers are hidden.
How do I only show the answer of the specific Question
container?
Example:
- How does this work?
- What do you do?
click on 2
- How does this work?
- Answer to 1
- What do you do?
- Answer to 2
Instead of:
- How does this work?
- What do you do?
- Answer to 2
function Question(props) {
const [show, setShow] = useState(false);
const onClick = () => {
if (show) {
setShow(false);
} else {
setShow(true);
}
};
const questionList = props.questionList;
const questions = questionList.map(question => (
<div onClick={onClick} className="container">
<div className="line"></div>
<div className="question-container">
<h3 className="question">{question.question}</h3>
<div className="drop-icon">
<i className="fa-solid fa-caret-down"></i>
</div>
</div>
{show ? <Answer question={question} /> : null}
</div>
));
return <section>{questions}</section>;
}
function Answer(props) {
const question = props.question;
const answer = (
<div className="answer">
<p>{question.answer}</p>
</div>
);
return answer;
}
CodePudding user response:
It seems that the state show
is just one value while each item should probably have their own show
for the desired result.
Try make show
an object (or array) that stores a boolean
value for each item in the list:
function Question({ questionList }) {
const [show, setShow] = useState({});
const onClick = (index) =>
setShow((prev) => ({ ...prev, [index]: !Boolean(prev[index]) }));
const questions = questionList.map((question, index) => (
<div key={index} onClick={() => onClick(index)} className="container">
<div className="line"></div>
<div className="question-container">
<h3 className="question">{question.question}</h3>
<div className="drop-icon">
<i className="fa-solid fa-caret-down"></i>
</div>
</div>
{show[index] ? <Answer question={question} /> : null}
</div>
));
return <section>{questions}</section>;
}
Or consider to make each question a component QuestionItem
(like Answer
in the example) that has its own show
state:
const QuestionItem = ({ question }) => {
const [show, setShow] = useState(false);
const onClick = () => setShow((prev) => !prev);
return (
<div onClick={onClick} className="container">
<div className="line"></div>
<div className="question-container">
<h3 className="question">{question.question}</h3>
<div className="drop-icon">
<i className="fa-solid fa-caret-down"></i>
</div>
</div>
{show ? <Answer question={question} /> : null}
</div>
);
};
And iterate the component QuestionItem
in Question
:
function Question({ questionList }) {
const questions = questionList.map((question, index) => (
<QuestionItem key={index} question={question} />
));
return <section>{questions}</section>;
}