网络请求状态管理需统一状态源、贯穿全生命周期、防错乱。用单一对象管理isLoading/data/error/status,UI同步更新,重试静默、失败延迟提示,结合AbortController清理旧请求。

网络请求状态管理不是“加个 loading 变量”就完事,而是要把加载中、成功、失败、重试这四个状态串成一条可感知、可控制、不混乱的用户路径。核心是状态单一可信、UI 同步及时、用户操作有反馈。
统一状态源,避免多处维护
用一个对象或响应式变量集中描述当前请求全貌,比如:
`{ isLoading: true, data: null, error: null, status: 'retrying' }`。
不要拆成 isLoading、isSuccess、isFailed 三个布尔值——它们会相互覆盖、难以判断优先级。例如重试中既不是成功也不是失败,但 isLoading 为 true 是唯一确定事实。
- React 中用
useState或useReducer管理这个状态对象 - Vue 中用
ref或computed派生视图状态(如isIdle = !state.isLoading && !state.error && !state.data) - 纯 JS 场景下,用闭包 + 触发自定义事件(
dispatchEvent(new CustomEvent('request-state-change', { detail: newState })))通知 UI 更新
加载态贯穿整个生命周期,不只在首次请求
用户点一次按钮,从发起请求→失败→重试→再失败→最终放弃,全程应保持 UI 处于“处理中”状态,而不是闪一下又恢复可点击。
- 请求前设
isLoading = true,并禁用按钮、显示 spinner 或骨架屏 - 重试函数内部不修改 UI 状态,只专注发请求、等响应、抛错误
- 无论成功还是彻底失败(所有重试耗尽),都走同一个
finally分支设isLoading = false - 若需区分“初次加载”和“重试中”,可用
status: 'loading' | 'retrying'字段,配合文案提示:“正在重试…”
失败提示要延迟、具体、可操作
别一失败就弹 Toast。用户需要的是确定性反馈,不是干扰。
- 仅在最后一次重试失败后才触发 UI 提示,中间失败静默处理
- 提示内容明确三点:做什么失败了(如“提交订单”)、可能原因(如“网络不稳定”)、下一步动作(如“点击重试”或“检查网络”)
- 把原始请求参数缓存下来,“重试”按钮直接复用,不需用户重新填表单、选地址
- 关键操作(如支付、删除)失败时,用 Modal 弹层;普通列表加载失败,用顶部 Banner 或轻量 Toast 即可
结合 AbortController 防止状态错乱
用户快速连点、页面切换、输入未完成就离开——这些都会让旧请求还在跑,新状态已覆盖,导致 UI 显示和实际逻辑脱节。
- 每次请求前创建新的
AbortController,把signal传给fetch或 axios - 请求完成(无论成功失败)或组件卸载时,调用
controller.abort()清理挂起请求 - 在状态对象中增加
abortId字段,确保重试发起的新请求能正确中止上一轮残留任务 - 这样即使用户点了三次按钮,也只会有一个真实请求在运行,状态始终与最新操作对齐











