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

React组件状态设置异常求助:useEffect取数后状态未更新

问题描述

在React组件里用useEffect钩子通过axios实例http从API拿数据,状态定义是:

const [inputsData, setInputsData] = useState(false);

原useEffect代码如下:

useEffect(() => {
    if (active.id) {
        http.get(`/stock/${title}/${active.id}`).then((response) => {
            setInputsData(response.data);
            console.log(inputsData);
        });
    }
}, [title, active.id, refresh]);

原本期望title(URL路由参数)、active.id(当前展示项的React状态)或者refresh变量变化时,数据会刷新重渲染。但实际情况是:API返回的数据没问题,调用setInputsData后,console.log打出来的是旧状态,页面渲染的也是旧数据,得重新导航或刷新页面才能看到正确内容。具体表现就是:点a显示a的数据,点b还是显示a的数据,点c又显示b的数据。

试过模拟重新导航、先把状态设为false再赋值、给setState加setTimeout这些办法,都没用。

后来把useEffect删掉,换成下面这段代码:

if (active.id && !inputsData) {
    http.get(`/stock/${title}/${active.id}`).then((response) => {
        setInputsData(response.data);
        console.log(inputsData);
    });
}

点击按钮时把inputsData设为false,组件重渲染的时候就会重新从API拿新值,问题就解决了。

问题原因

  1. 异步请求竞态是核心问题:当title或active.id快速切换时,前一次的API请求可能比后一次请求晚完成。比如先点a发起请求A,紧接着点b发起请求B,如果请求A比请求B晚结束,那setInputsData就会被请求A的结果覆盖,导致页面显示的还是旧数据,这就出现了点b却显示a数据的情况。

  2. 原useEffect没处理请求取消:在依赖项变化时,前一次没完成的请求没有被取消,旧请求的结果会覆盖新请求的状态,这才是页面渲染旧数据的关键。而后来的写法,通过点击时重置inputsData为false,只有当inputsData为false时才发起新请求,相当于间接避免了旧请求结果覆盖新状态的问题。

  3. 关于console.log显示旧值:这是正常现象,因为setState是异步的,状态更新不会立刻生效,当前函数执行时拿到的还是旧的状态值,这个只是日志的问题,不是页面渲染旧数据的核心原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 09:40:20