I've been working on making quiz component in react native project. What I aim to build is like this screenshot shows below.
https://i.sstatic.net/khrDO.png
There's one problem I'm facing is that when a correct answer is selected, other options that were already selected become activated as same as the answer.
I want the selected incorrect answers are kept strike-through like the screenshot above after the correct answer is chosen.
Here's code that related to the issue.
const Quiz: React.FC<QuizProps> = ({
options,
correctAnswerIndex
}) => {
const [accSelectedOptionIdx, setAccSelectedOptionIdx] = useState<number[]>([]);
const isCorrectAnswer = (
selectedOption: number[],
correctAnswer: number[] | undefined
) => {
const matchCorrectIdxNumber = selectedOption.filter((ele) =>
correctAnswer?.includes(ele)
);
return matchCorrectIdxNumber.length === correctAnswer?.length;
};
const onPress = (idx: number) => {
if (!user) {
history.push('/login', {
from: pathname,
});
} else {
setAccSelectedOptionIdx((prev) => [...prev, idx]);
}
};
const isOptAlreadySelected = (idx: number) => {
const result = accSelectedOptionIndex.includes(idx);
return result;
};
return (
<View>
{options?.map((option, idx) => {
return (
<>
<TouchableOpacity
onPress={onPress(idx));
disabled={isCorrectAnswer(accSelectedOptionIndex, correctAnswerIndex)}
key={option}
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<Text
selectable
style={
isOptAlreadySelected(idx)
? // if an option being mapped over was already selected
isCorrectAnswer(accSelectedOptionIndex, correctAnswerIndex)
? // if the option that was already selected is correct answer, then apply correct type style to it
[styles.defaultOptionTxt, styles.correctAnswerTxt]
: // if it's incorrect answer, apply incorrect type style
[styles.defaultOptionTxt, styles.wrongAnswerTxt]
: // if an option is not selected yet, apply default style
styles.defaultOptionTxt
}
>
{option}
</Text>
(...omitted)
))}
A type of the data 'correctIndexes' from the code snippet is number array given by server.
ex) correctIndexes = [1]
My approach that has the issue is to compare an array that contains indexes accumulated by user selection and the correctAnswerIndex so I can check if there's the correctAnswerIndex number in the array.
However the bug I described occurs when the correct answer is selected, since the array 'accSelectedOptionIndex' has the correctAnswerIndex at the same time, which leads to change the strike-through options.
To fix this issue, the previous selected wrong options shouldn't be affected by clicking the answer option, which was caused by isCorrectAnswer(accSelectedOptionIndex, correctAnswerIndex) ? [styles.defaultOptionTxt, styles.correctAnswerTxt] : [styles.defaultOptionTxt, styles.wrongAnswerTxt]
.
Therefore, one can define status such as correct, wrong, default or yet for all three cases with comparing two arrays and index from the whole options, so that every time user clicks an option, it'll just have its own status that we defined, while not affecting to any other option.
{options?.map((option, idx) => {
const status = _.includes(accSelectedOptionIdx, idx)
? _.includes(correctIndexes, idx)
? 'correct'
: 'wrong'
: 'yet';
return (
<>
<TouchableOpacity
onPress={onPress(idx));
disabled={isCorrectAnswer(accSelectedOptionIndex, correctAnswerIndex)}
key={option}
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<Text
selectable
style={
styles.defaultOptionTxt,
status === 'correct'
? styles.correctAnswerTxt
: status === 'wrong'
? styles.wrongAnswerTxt
: {},
]}
>
{option}
</Text>
(...omitted)
))}