Next.js 13中useRouter为null、router.isReady失效问题求助
Next.js 13 useRouter 报错:Cannot read properties of null (reading 'useContext')
问题描述
我在使用Next.js 13时遇到了一个无法解决的错误,代码如下:
import { useRouter } from 'next/navigation'; async function getCheckoutInfo() { const router = useRouter(); if (router.isReady) { console.log('Router query:', router.query); } else { console.log('Router is not ready yet') } return 'test'; } export default async function CheckoutPage() { const info = await getCheckoutInfo(); return( <div> <h1>Checkout </h1> <p>{info}</p> </div> ) }
报错信息如下:
Unhandled Runtime Error Error: Cannot read properties of null (reading 'useContext') Call Stack Object.useContext webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react/cjs/react.shared-subset.development.js (1428:31) useRouter webpack-internal:///(sc_server)/./node_modules/next/dist/client/components/navigation.js (91:32)
我觉得useRouter没有按预期工作。之前用useEffect()能正常运行,但我以为Next.js 13里不需要这么做了。
问题原因
useRouter 是React Hook,必须严格遵循Hook规则:
- 只能在React组件的顶层调用,或者在自定义Hook的顶层调用
- 不能在普通异步函数(比如你的
getCheckoutInfo)里调用——这类函数不属于React组件或自定义Hook的执行上下文,无法获取React内部的Context,因此抛出useContext相关错误。
另外,你的getCheckoutInfo不是自定义Hook(自定义Hook必须以use开头命名),即便它是同步函数,也不能在组件内部的异步逻辑中调用。
解决办法
方法1:将逻辑改为自定义Hook(适合复用场景)
自定义Hook必须以use开头,且在组件顶层调用:
import { useRouter } from 'next/navigation'; // 自定义Hook,命名以use开头 function useCheckoutInfo() { const router = useRouter(); if (router.isReady) { console.log('Router query:', router.query); } else { console.log('Router is not ready yet') } return 'test'; } export default function CheckoutPage() { // 在组件顶层调用自定义Hook const info = useCheckoutInfo(); return( <div> <h1>Checkout </h1> <p>{info}</p> </div> ) }
方法2:直接在组件顶层使用useRouter(适合简单场景)
如果不需要复用逻辑,直接把路由相关代码放在组件顶层:
import { useRouter } from 'next/navigation'; export default function CheckoutPage() { const router = useRouter(); if (router.isReady) { console.log('Router query:', router.query); } else { console.log('Router is not ready yet') } return( <div> <h1>Checkout </h1> <p>test</p> </div> ) }
方法3:结合异步请求与路由信息
如果getCheckoutInfo需要基于路由参数做异步请求,可通过useEffect监听路由状态变化:
import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; export default function CheckoutPage() { const router = useRouter(); const [info, setInfo] = useState('Loading...'); useEffect(() => { async function fetchCheckoutInfo() { if (router.isReady) { console.log('Router query:', router.query); // 根据路由参数发起异步请求 const res = await fetch(`/api/checkout?orderId=${router.query.orderId}`); const data = await res.json(); setInfo(data.info); } } fetchCheckoutInfo(); }, [router.isReady, router.query]); return( <div> <h1>Checkout </h1> <p>{info}</p> </div> ) }
补充说明
Next.js 13 App Router中的useRouter确实无需像Pages Router那样必须依赖useEffect等待isReady,但前提是要在组件或自定义Hook的顶层正确调用它。普通异步函数不具备Hook的执行上下文,必然会报错。
内容的提问来源于stack exchange,提问作者Nothere
相关产品推荐
相关产品推荐

