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

React中setInterval读取useState队列始终为空的问题排查

问题原因与解决方案

问题原因

这是React组件里典型的闭包陷阱问题:

  • 你的useEffect依赖项是空数组[],意味着它只会在组件首次挂载时执行一次。
  • setInterval的回调函数在挂载时就被创建,它捕获的是当时的nums状态——也就是初始的空数组[]。
  • 后续点击按钮更新nums时,这个回调里的nums并不会同步更新,始终是挂载时的旧值,所以每次打印都是空数组,也没法正确处理队列元素。

解决方案

方案1:使用函数式更新setState

React的setState支持传入函数,函数参数是当前最新的状态值,能直接绕过闭包陷阱拿到最新的nums。修改useEffect内的代码:

import { useState, useEffect } from "react";

function App() {
  const [nums, setNums] = useState([]);

  useEffect(() => {
    const intervalId = setInterval(() => {
      setNums(prevNums => {
        console.log(`Nums > `, prevNums);
        const nextNums = [...prevNums];
        nextNums.pop();
        return nextNums;
      });
    }, 5000);
    return () => clearInterval(intervalId);
  }, []);

  return (
    <div>
      {JSON.stringify(nums)}
      <div>
        {[1, 2, 3, 4, 5, 6, 7, 8, 9].map((val) => {
          return (
            <div key={val} style={{ cursor: 'pointer' }} onClick={() => {
              setNums(prev => [...prev, val])
            }}>
              {val}
            </div>
          );
        })}
      </div>
    </div>
  );
}

export default App;

补充:把点击事件里的setNums也改成函数式更新,避免连续快速点击时丢失状态;同时给map元素加上key属性,符合React规范。

方案2:用useRef保存最新状态

如果需要在回调里直接读取最新状态,可以用useRef创建引用,每次nums更新时同步它的值:

import { useState, useEffect, useRef } from "react";

function App() {
  const [nums, setNums] = useState([]);
  const numsRef = useRef(nums);

  // 每次nums更新时同步ref的值
  useEffect(() => {
    numsRef.current = nums;
  }, [nums]);

  useEffect(() => {
    const intervalId = setInterval(() => {
      console.log(`Nums > `, numsRef.current);
      const nextNums = [...numsRef.current];
      nextNums.pop();
      setNums(nextNums);
    }, 5000);
    return () => clearInterval(intervalId);
  }, []);

  return (
    <div>
      {JSON.stringify(nums)}
      <div>
        {[1, 2, 3, 4, 5, 6, 7, 8, 9].map((val) => {
          return (
            <div key={val} style={{ cursor: 'pointer' }} onClick={() => {
              setNums([...nums, val])
            }}>
              {val}
            </div>
          );
        })}
      </div>
    </div>
  );
}

export default App;

内容的提问来源于stack exchange,提问作者noi.m

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 14:18:35