bk___
bk___

Reputation: 71

React - counting checked checkboxes

I am having some trouble with some checkboxes in my React component here: https://codesandbox.io/s/quiz-4uyde?file=/src/App.js

The problem I am getting is that when two correct answers are checked, the score is not being reflected correctly. I am trying to have it set up so that when a correct answer is checked, the score is increased by one. that increase should be removed when the correct answer is unchecked. Any the score should not be increased or decrease if an incorrect answer is checked. however, on the first question here, when I check one correct answer the score is increased, but when I check a second correct answer, the score is decreased.

If any has input, it would be appreciated!

Upvotes: 0

Views: 640

Answers (2)

Nemanja Lazarevic
Nemanja Lazarevic

Reputation: 1047

You should be using useState to track the checked answers throughout the quiz. In order to do that I've moved whole questions into the useState and added a new property to each checked: false.

const [questions, setQuestions] = useState(initialQuestions);

For managing user click you have a function handleAnswerOptionClick. The main takeaway from this function is that only clicked answer should have it's checked state toggled (checked: !previousCheckedValue). In relation to questions with type select when the user clicks on one question all others will be unchecked automatically.

const handleAnswerOptionClick = (e, questionId) => {
const answerTextValue = e.target.value;
const updatedQuestions = questions.map((question) => {
  if (question.id === questionId) {
    const updatedAnswersOptions = question.answerOptions.map((answer) => {
      if (answer.answerText === answerTextValue) {
        return { ...answer, checked: !answer.checked };
        } else {
          return question.questionType === "select"
            ? { ...answer, checked: false }
            : answer;
        }
      });
      return { ...question, answerOptions: updatedAnswersOptions };
      } else {
       return question;
      }
    });
    setQuestions(updatedQuestions);
  };

In addition to managing the checked state, you can also include the useMemo hook to calculate the number of correct answers inside all questions. Please note that if the answer has selected multiple correct answers for a certain question the score will be increased by a number of correct answers.

    const score = useMemo(() => {
    return questions.reduce((acc, q) => {
      const correctAnswerSelected = q.answerOptions.reduce((acc, answer) => {
        if (answer.checked && answer.isCorrect) {
          acc = acc + 1;
        }
        return acc;
      }, 0);
      acc = acc + correctAnswerSelected;

      return acc;
    }, 0);
  }, [questions]);

Here's the working codesandbox: https://codesandbox.io/s/quiz-forked-vbt6o?file=/src/App.js

Upvotes: 1

Alex Boutin
Alex Boutin

Reputation: 187

I think you might be handling the state wrong. What you are doing is setting static items and checking on click if they are correct, but not if they aren't. this way here are whats hapenning wrong:

  1. You're not tracking what is and isn't checked
  2. You're not tracking a wrong answer, only if the answer is clicked.

What you could do instead, is set the checked inside you answerOptions:

answerOptions: [
        { answerText: "New York", isCorrect: false, checked: false },
        { answerText: "London", isCorrect: false, checked: false },
        { answerText: "Paris", isCorrect: true, checked: false },
        { answerText: "Dublin", isCorrect: true, checked: false }
      ]

Then, in your handleChange, pass the item and change the checked value to true.

After that, all you have to do is update the score:

setScore(score.filter(a => a.isCorrect && a.checked).length)

Note that this won't remove point for wrong answers, but you can also have it this way

setScore(answers.filter(a => a.isCorrect && a.checked).length - answers.filter(a => !a.isCorrect && a.checked).length)

and set answers to the current Question's answers

Edit

Forgot to mention about the answers in the last part.

Upvotes: 0

Related Questions