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

React类组件转函数组件后fetch结果useState赋值异常

问题根因

两个核心问题导致state读取异常:

  1. 闭包捕获旧值:函数组件每次render都会生成新的作用域,fetch的then回调里启动定时器时,引用的fetchForResults是当前render周期的旧函数,它闭包内捕获的submission还是初始值[],根本拿不到后续更新的state。类组件不存在这个问题是因为this是可变引用,读取this.state时永远能拿到最新值。
  2. setInterval调用写法错误:原代码写的setInterval(fetchForResults(data.id), 1000)会立刻执行一次fetchForResults,再把它的返回值(undefined)作为定时器回调传入,定时器后续执行时根本不会跑你的查询逻辑。类组件里写的setInterval(this.fetchForResults, 1000)是传的函数引用,写法本身是正确的。

另外原代码还有个逻辑错误:接口返回后还执行setSubmitting(true),提交完成应该把提交中的状态设为false。

修复方案

最简修复方式是直接使用then回调里拿到的接口返回data,不需要依赖state读取提交id,同时修正定时器的调用写法:

const [submitting, setSubmitting] = useState(false)
const [watingForResult, setWaitingForResult] = useState(false)
const [submission, setSubmission] = useState([]);
const [scoringResults, setScoringResults] = useState([]);
// 补全原代码缺失的state声明
const [result, setResult] = useState([]);
const [error, setError] = useState('');

function submitSubmission() {
    setSubmitting(true);
    setResult([]);
    setError('');

    const reqData = {
        code: btoa(code),
        language: { name: language.name },
        users: { username: parseLocalJwt().username },
        problem: { name: textToLowerCaseNoSpaces(problem.name) }
    }

    fetch(URL + '/submission', {
        method: 'POST',
        body: JSON.stringify(reqData),
        headers: new Headers({
            ...getAuthorization(),
            'Content-Type': 'application/json'
        })
    })
    .then(res => res.json())
    .then(resData => {
        // 修正状态逻辑:拿到返回后关闭提交中状态
        setSubmitting(false);
        setWaitingForResult(true);
        setSubmission(resData);

        window.secondsWaiting = new Date().getTime();
        // 修正定时器写法:传入箭头函数作为回调,不要直接执行目标函数
        window.resultsListener = setInterval(() => {
            // 直接用当前回调里拿到的最新resData,不需要读闭包里的旧state
            fetchForResults(resData.id)
        }, 1000);
    });
}

// 方法接收传入的提交id,不依赖闭包读取state
function fetchForResults(submissionId) {
    console.log('当前查询的提交id:' + submissionId)
    // 后续查询逻辑直接使用传入的submissionId即可
}

// 组件卸载时清除定时器,避免内存泄漏
useEffect(() => {
    return () => {
        if (window.resultsListener) clearInterval(window.resultsListener)
    }
}, [])

// 提交按钮
<button
   type="button"
   onClick={submitSubmission}>
   Submit!
</button>

如果业务中确实需要在任意位置读取最新的submission值,可以搭配useRef存储最新值副本,绕开闭包限制:

const [submission, setSubmission] = useState([]);
const submissionRef = useRef([]);

// 更新state时同步更新ref
const updateSubmission = (val) => {
    setSubmission(val);
    submissionRef.current = val;
}

// 任意位置需要读最新submission时,读取submissionRef.current即可

内容的提问来源于stack exchange,提问作者zemmsoares

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:01:18