I have DATA
array in which i store objects that contain sentences and answers. Each answer has its isCorrect
prop.
How do I check answer correctnes on button click?
After button click, correct answers should make <select>
tag border change to green and incorrect or undefined to red.
Parent component:
export default function App() {
const [isCorrect, setIsCorrect] = useState();
const [isChecked, setIsChecked] = useState(false);
const handleValueChange = (isCorrect) => {
setIsCorrect(isCorrect);
};
return (
<Wrapper>
{DATA.map((sentence, index) => (
<Sentence isCorrect={isChecked ? isCorrect : null}>
<span>
{index 1}. {sentence.sentenceFirstPart}
</span>
<select>
{sentence.answerOptions.map((option) => (
<option
onChange={() => handleValueChange(option.answerText)}
value={option.answerText}
>
{option.answerText}
</option>
))}
</select>
<span>{sentence.sentenceSecondPart}</span>
</Sentence>
))}
<button onClick={() => setIsChecked(true)}>Check</button>
</Wrapper>
);
}
Styled components:
const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
button {
padding: 0rem 1rem;
width: 6rem;
}
`;
export const Sentence = styled.div`
display: flex;
align-items: center;
span {
font-size: 1.2rem;
}
select {
margin: 0 0.5rem;
border: 1px solid;
padding: 0.2rem;
border-radius: 4px;
font-weight: 500;
border-color: ${({ isCorrect }) =>
isCorrect ? "green" : !isCorrect && isCorrect !== undefined ? "red" : ""};
}
`;
Test data:
const DATA = [
{
sentenceFirstPart: "It takes a lot of",
sentenceSecondPart: "to learn how to waterski properly",
answerOptions: [
{ answerText: "", isCorrect: false },
{ answerText: "attempt", isCorrect: false },
{ answerText: "effort", isCorrect: true },
{ answerText: "trial", isCorrect: false },
{ answerText: "try", isCorrect: false }
]
},
{
sentenceFirstPart: "It was Thomas Edison who ",
sentenceSecondPart: "electricity",
answerOptions: [
{ answerText: "", isCorrect: false },
{ answerText: "detected", isCorrect: false },
{ answerText: "invented", isCorrect: true },
{ answerText: "found", isCorrect: false },
{ answerText: "discovered", isCorrect: false }
]
}
];
CodePudding user response:
It seems that isCorrect
would need to record result of each questions and handleValueChange
should probably be called on change of select
to update the values in isCorrect
.
Forked example with modification: codesandbox
Here isCorrect
is updated as an object to save result of each question:
const [isCorrect, setIsCorrect] = useState({});
const [isChecked, setIsChecked] = useState(false);
const handleValueChange = (value, index) => {
setIsCorrect((prev) => ({
...prev,
[index]: value === "true" ? true : false,
}));
};
handleValueChange
modified to pass value
of option
and index
of the question, so isCorrect
can be updated accordingly:
<Wrapper>
{DATA.map((sentence, index) => (
<Sentence isChecked={isChecked} isCorrect={isCorrect[index]} key={index}>
<span>
{index 1}. {sentence.sentenceFirstPart}
</span>
<select onChange={(e) => handleValueChange(e.target.value, index)}>
{sentence.answerOptions.map((option, index) => (
<option value={option.isCorrect} key={index}>
{option.answerText}
</option>
))}
</select>
<span>{sentence.sentenceSecondPart}</span>
</Sentence>
))}
<button onClick={() => setIsChecked(true)}>Check</button>
</Wrapper>
In styled Sentence
the select
could take both isChecked
and isCorrect
(for this question) as conditions to set the border-color
.
export const Sentence = styled.div`
display: flex;
align-items: center;
span {
font-size: 1.2rem;
}
select {
margin: 0 0.5rem;
border: 2px solid;
padding: 0.2rem;
border-radius: 4px;
font-weight: 500;
border-color: ${({ isChecked, isCorrect }) =>
!isChecked ? "currentColor" : isCorrect ? "green" : "red"};
}
`