Home > database >  how to increment a state inside dot function in React.js
how to increment a state inside dot function in React.js

Time:12-09

so i'm basically trying to create a quiz app where i need to keep a track of score meaning how many times a user has clicked the right answer button,

so the issue is i've implemeted a logic about whenever a user clicks as follows; and i wanted to add an increment state when ever

i.id === selectedAnsId && i.answer === correctAns ? {
setScore(prev => prevScore   1)
}

Page1.jsx:

  function handleSelect(id, selectedAnsId) {
    
    setQuizData((prevQuizData) => {
      return prevQuizData.map((question) => {
        const correctAns = question.correct_answer;
        return question.id === id
          ? {
              ...question,
              answers: question.answers.map((i) => {
                return i.id === selectedAnsId
                  ? {
                      ...i,
                      selectedAns: i.answer,
                      isSelected: !i.isSelected
                    }
                    //the condition below is when i want to increment my state
                  : i.id === selectedAnsId && i.answer === correctAns
                  ? {
                      ...answer,
                      selectedAns: i.answer,
                      correctAns: selectedAns,
                      isSelected: !i.isSelected,                    / 

                   //here i want to increment my state
                    }
                 
                  : i.id === selectedAnsId && i.answer !== correctAns
                  ? {
                      ...answer,
                      selectedAns: i.answer,
                      isSelected: true
                    }
                    
                  : { ...i, isSelected: false };
              })
            }
          : question;
      });
    });
    
    console.log(count);
  }

so i tried to increment inside these dot fucntion, but the state did not change instead it kept logging 0 ,
i want to know a solution to increment (if posiible inside my ...fucntion) a state when the condition selectedAns is === correctAns is met, or even if it is possible to increment a state inside dot dunction

P.S i've even tried to increment it outside the dot fucntion

CodePudding user response:

React setStates are async. It means that your values are not updated immediately after your setState.

You're doing your setState in a loop. So when you update your state value, the next round of the loop executes faster than the time which is required for the component to use the updated value of that state.

In order to fix your issue, you can use another local variable and update that variable instead of your state and then finally after your loop, set your state:

function handleSelect(id, selectedAnsId) {
  //Added
  let newCount = count;

  setQuizData((prevQuizData) => {
    return prevQuizData.map((question) => {
      const correctAns = question.correct_answer;
      if(question.id === id) {
        return {
          ...question,
          answers: question.answers.map((i) => {
            if(i.id === selectedAnsId) {
              return {
                ...i,
                selectedAns: i.answer,
                isSelected: !i.isSelected
              };
            } else if(i.id === selectedAnsId && i.answer === correctAns) {
              //Added
              newCount  ;

              return {
                ...answer,
                selectedAns: i.answer,
                correctAns: selectedAns,
                isSelected: !i.isSelected,
              };
            } else if(i.id === selectedAnsId && i.answer !== correctAns) {
              return {
                ...answer,
                selectedAns: i.answer,
                isSelected: true
              };
            } else {
              return { ...i, isSelected: false };
            }
          })
        }
      } else {
        return question;
      }
    });
  });

  //Added
  setCount(newCount);
  console.log(newCount);
}

And you can see your changes on count using useEffect:

useEffect(() => {
  console.log(count);
}, [count]);

CodePudding user response:

If you necessarily want to increment at the place where you placed the comment, you could add a immediately invoked function like this:

function handleSelect(id, selectedAnsId) {
  setQuizData((prevQuizData) => {
    return prevQuizData.map((question) => {
      const correctAns = question.correct_answer;
      return question.id === id
          ? {
              ...question,
              answers question.answers.map((i) => {
                return i.id === selectedAnsId
                  ? {
                      ...i,
                      selectedAns: i.answer,
                      isSelected: !i.isSelected,
                    }
                  : //the condition below is when i want to increment my state
                  i.id === selectedAnsId && i.answer === correctAns
                  ? (() => {
                      //here i want to increment my state
                      setScore((prev) => prevScore   1);

                      return {
                        ...answer,
                        selectedAns: i.answer,
                        correctAns: selectedAns,
                        isSelected: !i.isSelected,
                      };
                    })()
                  : i.id === selectedAnsId && i.answer !== correctAns
                  ? {
                      ...answer,
                      selectedAns: i.answer,
                      isSelected: true,
                    }
                  : { ...i, isSelected: false };
              }),
            }
          : question;

    });
  });
}

But I think it would be way better to imply from the selected answer whether it was correct, and increment the score before the return part inside .map(), somewhat like this:


function handleSelect(id, selectedAnsId) {
  setQuizData((prevQuizData) => {
    return prevQuizData.map((question) => {
      const correctAns = question.correct_answer;

      const hasUserAnsweredCorrectly =
        i.id === selectedAnsId && i.answer === correctAns;

      if (hasUserAnsweredCorrectly) {
        setScore((prev) => prevScore   1);
      }

      return question.id === id
        ? {
            ...question,
            answers: question.answers.map((i) => {
              return i.id === selectedAnsId
                ? {
                    ...i,
                    selectedAns: i.answer,
                    isSelected: !i.isSelected,
                  }
                : 
                hasUserAnsweredCorrectly
                ? {
                    ...answer,
                    selectedAns: i.answer,
                    correctAns: selectedAns,
                    isSelected: !i.isSelected,
                  }
                : i.id === selectedAnsId && i.answer !== correctAns
                ? {
                    ...answer,
                    selectedAns: i.answer,
                    isSelected: true,
                  }
                : { ...i, isSelected: false };
            }),
          }
        : question;
    });
  });
}
  • Related