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

React中useState更新后获取仍为旧值的问题求助

调用异步刷新函数后状态先更新又回退的解决办法

我编写了用于刷新状态的异步函数refreshAfterCreate:

const refreshAfterCreate = async () => {
  try {
    const res = await fetch(process.env.NEXT_PUBLIC_MICROSERVICE_COMPANY_URL + '/companies', {method: 'GET'});
    const data = await res.json();
    await setCompanies(data);
  } catch (error) {
    console.error('Error al realizar el fetch:', error);
  }
  try {
    const res = await fetch(process.env.NEXT_PUBLIC_MICROSERVICE_SERVICE_URL + '/services', {method: 'GET'});
    const data = await res.json();
    await setServices(data);
  } catch (error) {
    console.error('Error al realizar el fetch:', error);
  }
};

使用await调用该函数后,立刻执行console.log(companies)和console.log(services)输出的仍是旧数据。我尝试添加以下useEffect监听状态变化:

useEffect(() => {
  console.log('Companies Updated', companies);
}, [companies]);

useEffect(() => {
  console.log('Services Updated', services);
}, [services]);

这些useEffect能正确打印更新后的值,但日志显示状态先更新又变回旧值,如图所示:
状态更新后回退的日志


问题原因

  1. React状态更新是异步操作,setCompanies这类状态 setter 本身不返回Promise,await setCompanies(data)没有实际作用,无法等待状态更新完成。
  2. 如果refreshAfterCreate定义在某个闭包(比如组件初始渲染的回调)中,可能会捕获旧的状态或依赖,导致更新后被其他逻辑覆盖。
  3. 调用refreshAfterCreate的场景(比如表单提交)可能触发了页面默认刷新,导致组件重新渲染,状态回到初始值。

解决步骤

1. 移除无效的await调用

状态 setter 不是异步函数,不需要用await等待,直接调用即可:

const refreshAfterCreate = async () => {
  try {
    const res = await fetch(`${process.env.NEXT_PUBLIC_MICROSERVICE_COMPANY_URL}/companies`, {method: 'GET'});
    const data = await res.json();
    setCompanies(data); // 去掉多余的await
  } catch (error) {
    console.error('获取公司列表失败:', error);
  }
  try {
    const res = await fetch(`${process.env.NEXT_PUBLIC_MICROSERVICE_SERVICE_URL}/services`, {method: 'GET'});
    const data = await res.json();
    setServices(data); // 去掉多余的await
  } catch (error) {
    console.error('获取服务列表失败:', error);
  }
};

2. 用useCallback包裹刷新函数,避免闭包陷阱

如果函数依赖组件内的变量或状态,用useCallback包裹确保它能获取最新的依赖:

import { useCallback } from 'react';

// ...

const refreshAfterCreate = useCallback(async () => {
  try {
    const res = await fetch(`${process.env.NEXT_PUBLIC_MICROSERVICE_COMPANY_URL}/companies`, {method: 'GET'});
    const data = await res.json();
    setCompanies(data);
  } catch (error) {
    console.error('获取公司列表失败:', error);
  }
  try {
    const res = await fetch(`${process.env.NEXT_PUBLIC_MICROSERVICE_SERVICE_URL}/services`, {method: 'GET'});
    const data = await res.json();
    setServices(data);
  } catch (error) {
    console.error('获取服务列表失败:', error);
  }
}, []); // 若有其他依赖(如状态、props),需添加到数组中

3. 检查调用场景,阻止默认行为

如果是在表单提交时调用refreshAfterCreate,一定要阻止表单默认的页面刷新行为:

const handleSubmit = async (e) => {
  e.preventDefault(); // 关键:阻止页面刷新导致状态重置
  // 先执行创建操作
  await createNewItem();
  // 再调用刷新
  refreshAfterCreate();
};

4. 排查是否有其他状态重置逻辑

在状态 setter 中添加临时日志,定位是否有其他代码修改状态:

setCompanies((prevState) => {
  console.log('公司状态更新前:', prevState, '更新后:', data);
  return data;
});

setServices((prevState) => {
  console.log('服务状态更新前:', prevState, '更新后:', data);
  return data;
});

通过日志可以确认是否有其他操作在覆盖最新的状态值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 10:27:47