多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
相关产品推荐
相关产品推荐

