使用next/router重定向时触发Invalid hook call错误的解决咨询
修复Next.js中useRouter钩子调用无效的错误
错误原因
你遇到的Invalid hook call错误,是因为**useRouter是React Hook,必须严格遵循Hook规则:只能在函数组件的顶层作用域,或者自定义Hook的顶层调用**。你现在把它放在了普通异步函数DispatchApi里,违反了这个规则,所以触发报错。
解决方案
下面提供两种可行的修复方式,根据你的使用场景选择:
方案一:从调用组件传递router实例
既然普通函数不能用Hook,就从调用DispatchApi的React组件中获取router实例,再传递给函数:
修改DispatchApi函数,新增router参数:
import { Axios } from '../axios' import { Languages } from '../business/language' import { NextRouter } from 'next/router' export async function DispatchApi({ address, sendedData, lan = Languages.fa, method, router, }: { address: string sendedData: string lan: Languages method: 'POST' | 'GET' router: NextRouter }) { let data = JSON.parse(sendedData) // 添加请求拦截器 const interceptorId = Axios.interceptors.request.use((config) => { router.push('login') return config }) try { const response = await Axios({ url: address, data, method, headers: { accept: '*/*', 'Accept-Language': lan, 'Content-Type': 'application/json', }, }) return response.data } finally { // 必须移除拦截器,避免重复添加导致内存泄漏或多次跳转 Axios.interceptors.request.eject(interceptorId) } }
在调用该函数的组件中,用useRouter获取实例并传递:
import { useRouter } from 'next/router' import { DispatchApi } from './path/to/DispatchApi' import { Languages } from '../business/language' export default function MyComponent() { const router = useRouter() const handleApiRequest = async () => { const result = await DispatchApi({ address: '/api/user', sendedData: JSON.stringify({ id: 1 }), lan: Languages.fa, method: 'POST', router, // 传递router实例 }) // 处理接口返回结果 } return <button onClick={handleApiRequest}>发起请求</button> }
方案二:直接导入Next.js的router实例(仅客户端场景)
Next.js提供了无需Hook的全局router实例,适合在纯客户端环境的普通函数中使用:
修改DispatchApi函数:
import { Axios } from '../axios' import { Languages } from '../business/language' import router from 'next/router' // 直接导入全局router实例 export async function DispatchApi({ address, sendedData, lan = Languages.fa, method, }: { address: string sendedData: string lan: Languages method: 'POST' | 'GET' }) { let data = JSON.parse(sendedData) const interceptorId = Axios.interceptors.request.use((config) => { router.push('login') return config }) try { const response = await Axios({ url: address, data, method, headers: { accept: '*/*', 'Accept-Language': lan, 'Content-Type': 'application/json', }, }) return response.data } finally { Axios.interceptors.request.eject(interceptorId) } }
⚠️ 注意:这个方法不能在服务器端渲染(SSR)场景使用,比如getServerSideProps、getStaticProps中,因为全局router实例仅在浏览器环境存在。
额外注意事项
- 无论哪种方案,都要在请求完成后用
eject移除Axios拦截器,否则每次调用函数都会新增拦截器,导致重复跳转和内存泄漏。 - 如果你的接口调用涉及SSR场景,建议优先用方案一,或者在服务器端直接通过
res.redirect处理重定向逻辑。
内容的提问来源于stack exchange,提问作者user18209107
相关产品推荐
相关产品推荐

