React useEffect中axios请求被重复取消两次的原因排查
问题根因
出现两次请求取消,是写法问题叠加React 18开发环境规则共同导致的:
- React 18 开启严格模式(
<StrictMode>)时,开发环境会对首次加载的组件执行 挂载→卸载→二次挂载 的流程,用来提前检测副作用未正确清理的问题。这个流程会触发一次你写在useEffect返回值里的controller.abort(),对应第一次请求取消。 - 你把AbortController的signal直接写在了axios实例的全局默认配置里,所有通过这个
api实例发出的请求都会共用同一个signal。AbortController的abort()调用是不可逆的,第一次触发abort之后,这个controller对应的signal会永久处于已中止状态,后续二次挂载时再通过同一个实例发请求,请求会直接被标记为取消,这就是你看到的第二次取消记录。
完整执行流程和日志表现完全对应:
- 组件首次挂载,执行useEffect逻辑:发起第一个请求,控制台打印
mounting - 严格模式触发组件卸载,执行清理函数:调用
controller.abort()取消第一个请求,控制台打印unmounting,此时全局定义的controller已经永久失效 - 严格模式触发组件二次挂载,再次执行useEffect逻辑:发起第二个请求,但因为实例绑定的signal早已是中止状态,请求直接被取消,出现第二条取消日志
修复方法
不要把固定的signal绑定到axios实例的全局配置上,每次执行副作用、发起请求时创建独立的AbortController实例即可:
// 移除axios实例配置里的signal字段,不要全局绑定固定signal const api = axios.create({ baseURL: 'http://localhost:8000/api/posts/', headers: { "Content-Type": "application/json", "Accept": "application/json", }, }) // useEffect里每次执行都生成独立的controller useEffect(() =>{ // 为本次副作用创建专属controller,仅在当前组件卸载时中止本次请求 const controller = new AbortController() api.get('/', { signal: controller.signal }).then(res =>{ console.log(res.data) }) console.log('mounting') return () =>{ controller.abort() console.log('unmounting') } }, [])
如果需要全局统一处理请求中止逻辑,可以通过axios请求拦截器为每个请求单独生成新的signal,不要让所有请求复用同一个controller实例。
内容的提问来源于stack exchange,提问作者Melly
相关产品推荐
相关产品推荐

