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

多请求写入数组状态变量导致状态不一致问题排查

解决React异步请求状态数组无法正确累积的问题

你的问题出在闭包捕获旧状态上:每个异步请求的finally块里,flashingBoxLoaderItems是请求发起时捕获的旧状态快照。当多个请求几乎同时完成时,每个setFlashingBoxLoaderItems([...flashingBoxLoaderItems, 'fetchN'])都是基于同一个旧数组更新,导致后面的更新会覆盖前面的,最终数组里只保留最后几个请求的凭证。

修复方案:使用函数式更新

React的setState支持传入函数,函数会接收最新的状态值作为参数,这样就能确保每次更新都是基于最新的数组:

修改每个请求的finally部分:

const fetch1 = async() => {
   try {
    const response = await get<any>("/url1/");
    //...
   } catch {
    //...
   } finally {
    // 用函数式更新获取最新状态
    setFlashingBoxLoaderItems(prevItems => [...prevItems, 'fetch1']);
   }
}

同理修改fetch2、fetch3等所有请求的setState逻辑,这样不管请求完成顺序如何,数组都会正确累积所有凭证。

额外优化:避免重复添加(可选)

如果担心某个请求可能重复执行(比如误触发多次),可以在更新时检查是否已存在该凭证,避免数组里出现重复项:

setFlashingBoxLoaderItems(prevItems => {
  if (!prevItems.includes('fetch1')) {
    return [...prevItems, 'fetch1'];
  }
  return prevItems; // 已存在则不修改
});

或者直接使用Set类型存储状态,天然去重:

// 初始化状态为Set
const [flashingBoxLoaderItems, setFlashingBoxLoaderItems] = useState<Set<string>>(new Set());

// 请求的finally里更新Set
setFlashingBoxLoaderItems(prevSet => new Set(prevSet).add('fetch1'));

// 校验所有请求完成的逻辑
useEffect(() => {
    const fetchesExpected = ['fetch1','fetch2','fetch3','fetch4','fetch5'];
    const result = fetchesExpected.every(i => flashingBoxLoaderItems.has(i));
    setFlashingBoxLoaderComplete(result);
}, [flashingBoxLoaderItems]);

简化状态:去掉单独的complete变量(可选)

其实flashingBoxLoaderComplete不需要单独作为状态存储,可以用useMemo直接计算得出,减少不必要的状态更新:

const fetchesExpected = ['fetch1','fetch2','fetch3','fetch4','fetch5'];
const flashingBoxLoaderComplete = useMemo(() => {
  return fetchesExpected.every(i => flashingBoxLoaderItems.includes(i));
}, [flashingBoxLoaderItems]);

这样就可以删掉原来的flashingBoxLoaderComplete状态和对应的useEffect,代码更简洁。

内容的提问来源于stack exchange,提问作者gene b.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 22:42:24