Next.js 14.0.4中app路由HOC使用useRouter报location未定义错误
Next.js App Router中HOC使用useRouter报错:location is not defined
问题详情
在Next.js App Router模式下,在高阶组件(HOC)中从next/navigation导入useRouter时,抛出以下错误:
node_modules/next/dist/client/components/app-router.js
ReferenceError: location is not defined
相关代码如下:
调用HOC的组件
const AccountsTypesWrapper = () => { const dispatch = useDispatch(); return ( <> <SubHeader pageLink={pageLinks.account.subMenu} title="Accounts" form={{ label: "Add Account Types" }} createPermission={Permissions.ACCOUNT_TYPE_CREATE} formHandler={() => dispatch( accountsAction.onAction({ key: AccountsModuleItems.ACCOUNT_TYPES, actionType: "CREATE", }) ) } /> <NestedHeader links={pageLinks.account.nestedMenu.accounts} label="Accounts" /> <AccountsTypesModals /> <AccountTypesTable /> </> ); }; export default withPermission( AccountsTypesWrapper, Permissions.ACCOUNT_TYPE_READ );
HOC代码
const withPermission = ( WrappedComponent: React.ComponentType<any>, requiredPermission: Permissions ) => { const WithPermission: React.FC<any> = (props) => { const router = useRouter(); const hasPermission = usePermissionCheck(requiredPermission); if (!hasPermission) { router.push("/"); } return hasPermission ? ( <WrappedComponent {...props} /> ) : ( <Loading isFullSize={true} /> ); }; return WithPermission; }; export default withPermission;
问题原因
- 客户端组件约束:App Router中
useRouter只能在客户端组件中使用,若HOC未标记为客户端组件,或被用于包装服务端组件,会因服务端环境不存在浏览器location对象报错。 - 渲染阶段副作用:直接在组件渲染逻辑中调用
router.push违反React渲染规则,属于非法副作用。
解决方案
- 标记HOC为客户端组件:在HOC文件顶部添加
'use client'指令,确保useRouter运行在客户端环境。 - 用useEffect执行导航:将
router.push放入useEffect中,避免渲染阶段触发副作用。 - 处理权限检查边界状态:确保权限检查完成后再执行导航或渲染,避免界面闪烁。
修正后的HOC代码
'use client'; // 必须添加,标记为客户端组件 import { useEffect } from 'react'; import { useRouter } from 'next/navigation'; const withPermission = ( WrappedComponent: React.ComponentType<any>, requiredPermission: Permissions ) => { const WithPermission: React.FC<any> = (props) => { const router = useRouter(); const hasPermission = usePermissionCheck(requiredPermission); useEffect(() => { // 仅在权限检查完成且无权限时执行导航 if (!hasPermission) { router.push("/"); } }, [hasPermission, router]); // 权限未确认前保持加载状态 if (hasPermission === undefined) { return <Loading isFullSize={true} />; } return hasPermission ? ( <WrappedComponent {...props} /> ) : null; // 导航后无需渲染加载组件,避免闪烁 }; return WithPermission; }; export default withPermission;
额外注意事项
- 确保
usePermissionCheck返回明确状态(比如undefined表示正在检查),避免权限未确定时触发错误导航。 - 若被HOC包装的组件是服务端组件,HOC标记为客户端组件后,包装后的组件会自动转为客户端组件,符合App Router规则。
内容的提问来源于stack exchange,提问作者Ebrahim Khalil Amid
相关产品推荐
相关产品推荐

