Состояние реакции не обновляется и обновляется старыми данными, когда приходят новые

когда я использую updateCorrectAnswers с useEffect ниже. это не обновляет мои правильные ответы. он показывает только пустой массив. когда приходит новый набор вызовов API, он показывает мои старые данные. Я не понимаю, почему. изображение console.info, которое показывает старые данные и пустые данные

Я пересмотрел некоторые сообщения об этом stackoverflow, но в основном это касается useEffect, но я пытаюсь использовать его внутри useEffect. это весь код, если кому нужно https://github.com/hyklops/react-starter/tree/master/quiz-app

function App() {
  const [trivias, setTrivias] = useState(null);
  const [isFetched, setIsFetched] = useState(false);
  const [correctAnswers, setCorrectAnswers] = useState([]);

  const updateCorrectAnswers = () => {
    trivias.map((trivia) => {
      setCorrectAnswers((prev) => [...prev, trivia.correct_answer]);
    });
  };

  async function dataFetch() {
    const res = await fetch(
      "https://opentdb.com/api.php?amount=5&type=multiple"
    );
    const data = await res.json();
    return setTrivias(data.results);
  }

  const shuffle = (trivia, index) => {
    const answers = [...trivia.incorrect_answers, trivia.correct_answer];
    const shuffledAnswers = getRandomAnswers(answers);

    // const shuffleArray = (answer) => [...array].sort(() => Math.random() - 0.5);
    return shuffledAnswers;
  };

  const getRandomAnswers = (answers) => {
    const newAnswers = [];

    while (newAnswers.length !== 4) {
      const getRandomIndex = Math.floor(Math.random() * 4);

      const condition = newAnswers.some(
        (item) => item === answers[getRandomIndex]
      );

      if (!condition) {
        newAnswers.push(answers[getRandomIndex]);
      }
    }

    return newAnswers;
  };

  const getTrivias = () => {
    return trivias.map((trivia, index) => {
      return <Trivia question = {trivia.question} answers = {shuffle(trivia)} />;
    });
  };

  useEffect(() => {
    dataFetch();
  }, []);

  useEffect(() => {
    if (!!trivias) {
      setIsFetched(true);
      updateCorrectAnswers();
      console.info({ correctAnswers });
    }
  }, [trivias]);

  if (!isFetched) {
    return <h1>loading</h1>;
  }

  return (
    <div className = "App">
      <div>{getTrivias()}</div>
      <div className = "check">
        <button>Check Answers</button>
      </div>
    </div>
  );
}

export default App;

Я пробовал использоватьEffect, и это не сработало.

Если вы думаете, что он не обновляется только потому, что журнал показывает пустой массив, setState является асинхронным, и оператор console.info вызывается до того, как setCorrectAnswers завершится.

WebbH 01.12.2022 21:47
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
1
160
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Это связано с тем, что вы вызываете console.info в той же функции, что и функцию для установки правильных ответов. Когда вы обновляете состояние, это не происходит синхронно в одном и том же рендере, поэтому, когда вы регистрируете correctAnswers сразу после updateCorrectAnswers, состояние по-прежнему []. Но когда вы меняете состояние, запускается повторный рендеринг, в котором состояние теперь является обновленным состоянием. Чтобы увидеть это, вы можете просто вставить console.info где-нибудь в своем приложении, например:

function App() {
  const [trivias, setTrivias] = useState(null);
  const [isFetched, setIsFetched] = useState(false);
  const [correctAnswers, setCorrectAnswers] = useState([]);

  console.info({ correctAnswers });
  
  const updateCorrectAnswers = () => {
    trivias.map((trivia) => {
      setCorrectAnswers((prev) => [...prev, trivia.correct_answer]);
    });
  };

Или просто визуализировать его на экране:

return (
    <div className = "App">
      <div>{getTrivias()}</div>
      <div>{correctAnswers}</div>
      <div className = "check">
        <button>Check Answers</button>
      </div>
    </div>
  );

Эта статья в документе может помочь лучше понять это.

Когда вы вызываете «updateCorrectAnswers();», правильные ответы обновляются только при следующем рендеринге. Журнал вашей консоли работает в том же рендере со старыми результатами.

Проблема в том, что вы получаете доступ к значению той же переменной состояния correctAnswers на уровне, когда вы обновляете. Обновленное значение будет доступно только в следующем рендере.

Вместо этого вы можете использовать useEffect, как показано ниже.

useEffect(() => {
    if (isFetched) {
      console.info({ correctAnswers });
    }
  }, [isFetched]);

Другие вопросы по теме