You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React State更新异常:新数据到来时显示旧数据或空数组

问题:useEffect中更新correctAnswers状态异常

在useEffect内调用updateCorrectAnswers函数时,correctAnswers状态存在异常:初始显示为空数组;发起新API请求获取数据后,状态却显示旧数据。相关代码如下:

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);

    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.log({ 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;

问题原因

  1. 状态更新异步特性:React的setState是异步操作,调用updateCorrectAnswers后立刻console.log(correctAnswers),此时获取的是更新前的旧状态,因为状态更新还未完成。
  2. 多次setState导致的异常:updateCorrectAnswers中通过map循环多次调用setCorrectAnswers,每次异步更新都会依赖当时的prev状态,循环中的多次异步更新会导致状态累积逻辑混乱,且效率低下。
  3. 闭包陷阱:监听trivias的useEffect中,correctAnswers被闭包捕获的是初始值,所以直接打印无法看到最新状态。

修复方案

1. 一次性生成正确答案数组

修改updateCorrectAnswers,直接生成完整的正确答案数组后一次性更新状态,避免多次调用setState:

const updateCorrectAnswers = () => {
  const newCorrectAnswers = trivias.map(trivia => trivia.correct_answer);
  setCorrectAnswers(newCorrectAnswers);
};

2. 正确监听状态更新结果

如果需要确认状态更新后的结果,不要在调用setState后立刻打印,新增一个监听correctAnswers的useEffect:

useEffect(() => {
  console.log("更新后的correctAnswers:", correctAnswers);
}, [correctAnswers]);

3. 简化逻辑,合并状态更新

可以在dataFetch中直接处理正确答案,减少额外的useEffect依赖:

async function dataFetch() {
  const res = await fetch("https://opentdb.com/api.php?amount=5&type=multiple");
  const data = await res.json();
  setTrivias(data.results);
  // 直接生成并更新正确答案数组
  setCorrectAnswers(data.results.map(trivia => trivia.correct_answer));
  setIsFetched(true);
}

同时移除原监听trivias的useEffect内的updateCorrectAnswers调用,简化整体逻辑。


内容的提问来源于stack exchange,提问作者Emin Çoşkun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:55:20