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

多useEffect场景下如何保证网络请求的执行顺序?

解决方案

核心思路是通过状态标记GET请求完成状态,确保POST/PATCH逻辑仅在初始数据加载完成后执行,同时处理异步请求的竞态问题。

步骤1:添加数据加载状态

新增状态跟踪初始GET请求是否完成,同时加入请求取消控制器处理竞态:

const [isDataLoaded, setIsDataLoaded] = useState(false);
const abortControllerRef = useRef<AbortController | null>(null);

步骤2:修改GET请求的useEffect

更新GET请求逻辑,添加请求取消机制,完成后标记数据加载状态:

useEffect(() => {
  // 取消上一次未完成的请求,避免旧请求覆盖新数据
  abortControllerRef.current?.abort();
  const controller = new AbortController();
  abortControllerRef.current = controller;

  getMacroNutrientProgressOnDate(selectedDate, { signal: controller.signal })
    .then((result) => {
      if (result) {
        const cacheKey = getCacheKey(selectedDate);
        progressCache.current[cacheKey] = {
          currentCalories: result.current_calories
        };
        setCurrentCalories(result.current_calories);
      }
      // 无论是否获取到数据,都标记加载完成,避免阻塞后续操作
      setIsDataLoaded(true);
    })
    .catch((err) => {
      if (err.name !== 'AbortError') {
        console.error('获取进度失败:', err);
        setIsDataLoaded(true);
      }
    });

  // 组件卸载或依赖变化时取消请求
  return () => controller.abort();
}, [selectedDate]);

步骤3:修改POST/PATCH的useEffect

调整逻辑,确保仅在数据加载完成后执行操作,同时完善依赖项:

useEffect(() => {
  // 初始渲染或数据未加载完成时直接返回
  if (!isDataLoaded) return;

  const cacheKey = getCacheKey(selectedDate);
  const existingEntry = progressCache.current[cacheKey];

  if (existingEntry) {
    console.log("Do a PATCH");
    // 补充你的PATCH请求逻辑:updateMacroNutrientProgressOnDate(selectedDate, currentCalories)
  } else {
    createMacroNutrientProgressOnDate(selectedDate, currentCalories)
      .then(result => {
        if (result) {
          progressCache.current[cacheKey] = { currentCalories };
        }
      })
      .catch(err => {
        console.error('创建进度失败:', err);
        // 捕获数据库唯一约束异常,同步已有数据到缓存
        if (err.code === 'YOUR_UNIQUE_CONSTRAINT_ERROR_CODE') {
          getMacroNutrientProgressOnDate(selectedDate)
            .then(existingResult => {
              if (existingResult) {
                progressCache.current[cacheKey] = { currentCalories: existingResult.current_calories };
                setCurrentCalories(existingResult.current_calories);
              }
            });
        }
      });
  }
}, [currentCalories, isDataLoaded, selectedDate]);

额外优化说明

  • 竞态防护:用AbortController取消未完成的请求,防止旧请求结果覆盖新数据。
  • 异常兼容:POST请求捕获唯一约束错误后,自动同步已有数据到缓存,避免后续重复触发错误。
  • 缓存稳定性:确保getCacheKey生成的键唯一且稳定,比如用YYYY-MM-DD格式的日期字符串,避免缓存匹配出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:21:12