Подсчет с использованием useState не обновляет состояние до вопроса 6, даже если на него дан правильный ответ.

#javascript #reactjs #react-hooks

Вопрос:

я пытаюсь создать приложение для викторины в react с помощью крючков. я хочу, чтобы ответы были доступны для клика, и после нажатия пользователь перейдет к следующему вопросу. Моя проблема в том, что состояние оценки не обновляется до вопроса 6! я делаю вызов API, чтобы получить вопросы и ответы с помощью useEffect. я знаю, что состояние использования асинхронно, и поэтому состояние не обновляется сразу, просто, даже если я правильно отвечу на первые 6 вопросов, после вопроса 6 оценка все равно будет 1. У кого-нибудь есть способ обойти это?

Мой вызов API с использованием useEffect:

 useEffect(() => {
  axios.get("https://my-quiz-server.herokuapp.com/api/newq").then((res) => {
      const allQuestions = res.data;
      setResult([allQuestions]);
    })
    .catch((error) => {
      console.log(error);
    });
}, [setResult]); 

Мой компонент викторины:

 import React, {
  useState,
  useContext,
  useEffect
} from "react";

import {
  QuizContext
} from "../Helpers/context";

const MainQuiz = () => {
  const {
    score,
    setScore,
    result
  } = useContext(QuizContext);

  const [currentQuestion, setCurrentQuestion] = useState(0);
  const [optionChosen, setOptionChosen] = useState("");
  console.log(optionChosen);
  console.log(result);

  const nextQuestion = (correctAnswer) => {
    if (optionChosen === correctAnswer) {
      setScore((score) => score   1);
    }
    setCurrentQuestion((currentQuestion) => currentQuestion   1);
  };

  useEffect(() => {
    console.log("score updated", score);
  }, [score]);
  return ( <
    div className = "quiz" > {
      result.map((question, index) => {
        if (currentQuestion < question.allQuiz.length) {
          return ( <
            h3 key = {
              index
            } > {
              question.allQuiz[currentQuestion].q_prompt
            } < /h3>
          );
        } else {
          return null;
        }
      })
    } <
    div className = "answer__container" > {
      result.map((answers, index) => {
        if (currentQuestion < answers.allQuiz.length) {
          return ( <
            div className = "answer__options" > {
              " "
            } <
            button className = "question__choices"
            onClick = {
              () => {
                setOptionChosen("a");
                nextQuestion(
                  result[0].allQuiz[currentQuestion].q_correctAnswer
                );
              }
            } >
            {
              answers.allQuiz[currentQuestion].a
            } <
            /button> <
            button className = "question__choices"
            onClick = {
              () => {
                setOptionChosen("b");
                nextQuestion(
                  result[0].allQuiz[currentQuestion].q_correctAnswer
                );
              }
            } >
            {
              answers.allQuiz[currentQuestion].b
            } <
            /button> <
            button className = "question__choices"
            onClick = {
              () => {
                setOptionChosen("c");
                nextQuestion(
                  result[0].allQuiz[currentQuestion].q_correctAnswer
                );
              }
            } >
            {
              answers.allQuiz[currentQuestion].c
            } <
            /button> <
            button className = "question__choices"
            onClick = {
              () => {
                setOptionChosen("d");
                nextQuestion(
                  result[0].allQuiz[currentQuestion].q_correctAnswer
                );
              }
            } >
            {
              answers.allQuiz[currentQuestion].d
            } <
            /button> <
            /div>
          );
        } else {
          return null;
        }
      })
    } <
    /div> <
    span > {
      score
    } < /span> <
    /div>
  );
};

export default MainQuiz; 

Комментарии:

1. В этом фрагменте слишком много неизвестных, чтобы знать, в чем может быть проблема. В качестве первого пункта при отладке вы пробовали: а) поместить точки останова внутрь nextQuestion , чтобы проверить, соответствуют ли correctAnswer и optionChosen вашим ожиданиям? б) проверка вашего ответа API, чтобы увидеть, есть ли в нем данные в той форме, которую вы ожидаете? (б), вероятно, имеет значение только в том случае, если correctAnswer это не то, что вы ожидаете, — особенно если это undefined так. а) на мой взгляд, это определенно отправная точка.)

2. ах, так что да, выбор варианта один позади, поэтому, когда вы нажимаете на первый вопрос, он регистрирует его как пустую строку

3. Кроме того, рабочий пример (возможно, в codesandbox.io) демонстрация проблемы действительно помогла бы людям помочь вам.

4. @Джеймс спасибо, что проверил это — видите, что я имею в виду, говоря о лучшей отправной точке для отладки? В любом случае, я приношу свои извинения, потому что я должен был заметить эту проблему. Это связано с тем , что обновления состояния реакции являются асинхронными, поэтому, когда вы setOptionChosen(something) , optionChosen не получите заданное вами значение до следующего рендеринга, то есть после того, как вы позвонили nextQuestion . Простое решение здесь, я думаю, состоит в том, чтобы optionChosen полностью выйти из состояния — вам, похоже, это не нужно для рендеринга или чего-то еще, поэтому просто передайте его в качестве дополнительного аргумента nextQuestion .

5. конечно — codesandbox.io/s/cool-moon-cmvbc?file=/src/App.js