Next.js中路由切换时如何在useEffect中取消Axios请求?
解决Next.js路由参数变化时取消Axios请求的问题
问题场景
在Next.js v12项目中使用Axios获取数据,每次router.query.pid变化时触发请求。若test 5的请求需5秒响应,此时快速切换到test 1,控制台会打印两个请求的结果;实际项目中用useState存储数据时,会出现旧请求的数据渲染到新页面的问题,因此需要在路由参数变化时取消未完成的之前请求。
修改方案
核心是利用AbortController配合useEffect的清理机制,确保路由参数变化时自动取消上一次未完成的请求:
- 将
AbortController放在useEffect作用域内,每次路由参数变化时创建新控制器,旧useEffect的清理函数负责取消之前的请求 - 在
useEffect的清理函数中执行请求取消操作 - 优化
fetchData函数参数,避免直接依赖router.query.pid,解决闭包导致的参数过期问题
修改后的前端代码
import React, { useEffect } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import axios from "axios"; const Test = () => { const router = useRouter(); const fetchData = async (pid, sec, signal) => { try { const res = await axios.get( `/api/test?pid=${pid}&sec=${sec}`, { signal } ); console.log(res.data); } catch (error) { // 忽略请求取消的错误,避免控制台冗余报错 if (!axios.isCancel(error)) { console.log(error); } } }; useEffect(() => { const abortController = new AbortController(); const { pid } = router.query; if (pid === "1") { fetchData(pid, 1000, abortController.signal); } else if (pid === "2") { fetchData(pid, 2000, abortController.signal); } else if (pid === "5") { fetchData(pid, 5000, abortController.signal); } // 路由参数变化时取消上一次未完成的请求 return () => { abortController.abort(); }; }, [router.query.pid]); return ( <> <ul> <li> <Link href="/test?pid=1">test1</Link> </li> <li> <Link href="/test?pid=2">test2</Link> </li> <li> <Link href="/test?pid=5">test5</Link> </li> </ul> </> ); }; export default Test;
关键说明
- 原写法中
fetchData内部创建的AbortController返回的清理函数并未被执行,因为useEffect没有调用该函数,导致旧请求无法取消 - 现在将
AbortController放在useEffect内部,每次路由参数变化时,useEffect的清理函数会自动调用abort()终止上一次请求 - 新增
axios.isCancel(error)判断,避免取消请求时控制台抛出不必要的错误
接口代码无需修改,保持原样即可。
内容的提问来源于stack exchange,提问作者Brandon Han
相关产品推荐
相关产品推荐

