React中useEffect结合AbortController状态更新异常问题
问题根源与解决方案
问题原因
你遇到的情况本质是:旧请求的响应可能在新请求完成后才返回,或者AbortController没能拦截到已经完成的请求(比如服务器响应过快,请求已经结束才触发abort),这时候旧请求的setData会覆盖新请求的状态。而你添加的setData('')只是重置了当前状态,但无法阻止后续旧请求的状态更新。
解决思路
除了用AbortController取消未完成的请求,还需要在更新状态前校验当前组件的logID是否和发起请求时的一致,确保只有对应请求的结果才会更新状态。
修改后的代码
useEffect(() => { const controller = new AbortController(); const signal = controller.signal; // 记录发起请求时的logID const currentLogID = router.query.logID; const fetchData = async () => { try { setData(''); const res = await axios.get(`/api/test?logID=${currentLogID}`, { signal }); // 校验当前组件的logID是否和请求时一致,一致才更新状态 if (router.query.logID === currentLogID) { setData(res.data); } } catch (error) { if (error.name !== 'AbortError') { console.error(error); } } }; if (currentLogID) { fetchData(); } return () => { controller.abort(); }; }, [router.query.logID]); // 移除setData,因为useState返回的setter是稳定的,无需加入依赖
额外说明
- 移除
setData的依赖:React官方明确说明,useState返回的状态更新函数是稳定引用,不会在组件重新渲染时变化,所以不需要加入useEffect的依赖数组,避免不必要的useEffect触发。 - 双重保险:
AbortController负责拦截未完成的请求,logID校验负责过滤已完成但过时的请求结果,两者结合彻底解决状态被旧请求覆盖的问题。
内容的提问来源于stack exchange,提问作者Brandon Han
相关产品推荐
相关产品推荐

