You need to enable JavaScript to run this app. NextJS普通函数内调用useRouter触发Invalid hook call报错
优惠活动
大模型
产品
解决方案
定价
更多

NextJS普通函数内调用useRouter触发Invalid hook call报错

报错根因拆解

React及Next.js封装的所有Hook(包括useRouter),合规的执行边界不是“任意JS函数的函数体”,而是React函数组件的渲染逻辑上下文、或以use开头命名的自定义Hook函数体,你当前的代码已经完全突破了这个边界:

  • 所有代码写在通用工具文件lib/api.js中,getRouterParams是普通业务工具函数:既不是React函数组件,也不符合自定义Hook必须以use开头的命名规范,执行时脱离了React的Hook校验上下文
  • 该函数被后续的异步方法getTown直接调用,执行场景处于服务端渲染的独立流程、完全不在React组件的渲染调用栈内,触发Hook调用时必然会被校验逻辑拦截,抛出Invalid hook call错误
  • 额外的认知偏差:你计划手动用query-string解析asPath获取查询参数的逻辑是完全冗余的——Next.js初始化路由实例时,已经自动完成了asPath中查询参数的结构化解析,直接读取router.query即可拿到完整参数键值对,不需要重复实现解析逻辑
对应解决思路

按照代码运行的不同场景选择适配的写法,不要强行在非组件上下文调用路由Hook:

组件/页面内获取参数

直接在React函数组件顶层调用useRouter即可,不需要额外封装工具函数:

// pages/xxx.js 或 components/xxx.js
import { useRouter } from 'next/router'

function TownPage() {
  // 组件顶层直接调用,完全符合Hook规则
  const router = useRouter()
  // router.query 即为自动解析好的结构化路由参数
  const townName = router.query.town
  return <div>当前页面所属城镇:{townName}</div>
}

如果需要复用路由加工逻辑,把封装方法改成符合规范的自定义Hook:

// hooks/useRouterParams.js
import { useRouter } from 'next/router'

// 自定义Hook必须以use开头,才能合法调用内置Hook
export function useRouterParams() {
  const router = useRouter()
  // 可自定义参数加工逻辑
  return {
    ...router.query,
    fullPath: router.asPath
  }
}

在组件中引入这个自定义Hook使用,不会触发任何Hook调用报错。

非组件上下文获取参数

在服务端逻辑、普通工具函数这类完全脱离React渲染流程的场景下,禁止调用任何React Hook,根据运行环境直接获取参数即可:

  • SSR流程(getServerSideProps):直接从页面上下文对象中拿参数,无需调用Hook:
export async function getServerSideProps(context) {
  // context.query 即为已解析好的路由查询参数
  const { town } = context.query
  // 直接把参数传入业务逻辑即可
  const townInfo = await getTown(town)
  return {
    props: { townInfo }
  }
}
  • 客户端工具逻辑:通过浏览器原生API解析当前页面参数,不依赖React上下文:
// 无React依赖的通用工具函数
export function getCurrentPageQuery() {
  if (typeof window === 'undefined') return {}
  // 用浏览器原生URL对象解析查询参数,无需额外依赖query-string
  const currentUrl = new URL(window.location.href)
  return Object.fromEntries(currentUrl.searchParams.entries())
}

注意:不要再通过router = withPageRouter(router)这类操作直接修改原路由实例,Next.js的router实例是单例全局对象,直接修改其属性会引发意料之外的状态不一致问题。


内容的提问来源于stack exchange,提问作者sylargaf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.01 11:54:05