You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

问题原因

  1. 客户端组件约束:App Router中useRouter只能在客户端组件中使用,若HOC未标记为客户端组件,或被用于包装服务端组件,会因服务端环境不存在浏览器location对象报错。
  2. 渲染阶段副作用:直接在组件渲染逻辑中调用router.push违反React渲染规则,属于非法副作用。

解决方案

  1. 标记HOC为客户端组件:在HOC文件顶部添加'use client'指令,确保useRouter运行在客户端环境。
  2. 用useEffect执行导航:将router.push放入useEffect中,避免渲染阶段触发副作用。
  3. 处理权限检查边界状态:确保权限检查完成后再执行导航或渲染,避免界面闪烁。

修正后的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 14:43:15