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

Next.js自定义useLocale钩子无限循环问题及解决方案

问题分析与解决方案

无限循环原因

  1. Next.js自动语言检测冲突:Next.js的i18n功能默认会优先匹配浏览器的语言偏好,即便你在next.config.js中设置了defaultLocale: 'en',当浏览器语言为法语时,仍会自动切换到fr locale。
  2. useEffect触发逻辑闭环:你的钩子中,当router.locale !== 'en'时会触发重定向到英文版本,但重定向完成后,Next.js又会因浏览器语言检测自动切回fr,导致useEffect再次触发重定向,形成无限循环。
  3. Strict Mode放大问题:开启reactStrictMode后,useEffect会执行两次,进一步加剧了循环频率,但核心矛盾仍为浏览器语言检测与强制重定向的冲突。

解决方案

方案1:使用Middleware强制默认英文(推荐)

通过Next.js Middleware在请求到达页面之前处理重定向,完全绕过客户端的语言检测逻辑,避免循环问题且性能更优。

在项目根目录创建middleware.js:

import { NextResponse } from 'next/server';

export function middleware(request) {
  const locale = request.nextUrl.locale;
  
  if (locale !== 'en') {
    return NextResponse.redirect(
      new URL(`/en${request.nextUrl.pathname}${request.nextUrl.search}`, request.url)
    );
  }
  
  return NextResponse.next();
}

export const config = {
  matcher: ['/:path*'], // 对所有路径生效
};

next.config.js保持原配置即可,Middleware会自动拦截并强制重定向到英文路径。

方案2:客户端修复逻辑并禁用自动语言检测

若需在客户端处理,可将初始化重定向逻辑移至_app.js,并修改useLocale钩子避免循环:

  1. 修改_app.js(或_app.tsx)
import { useEffect } from 'react';
import { useRouter } from 'next/router';

function MyApp({ Component, pageProps }) {
  const router = useRouter();

  useEffect(() => {
    // 仅首次挂载时执行一次,强制切换到英文
    if (router.locale !== 'en') {
      router.replace({ ...router, locale: 'en' });
    }
  }, []); // 空依赖数组,避免重复触发

  return <Component {...pageProps} />;
}

export default MyApp;
  1. 重构useLocale钩子
import { useRouter } from "next/router";
import { useCallback, useMemo } from "react";
import en from "@/../lang/en.json";
import fr from "@/../lang/fr.json";
import { flattenMessages } from "@/lang/flattenMessages";

const messages = {
    en,
    fr,
};

export const useLocale = () => {
    const router = useRouter();

    const flattenedMessages = useMemo(
        () => flattenMessages(messages[router.locale] || messages.en),
        [router.locale] // 精准依赖,减少不必要的重计算
    );

    const switchLocale = useCallback(
        (locale) => {
            if (locale === router.locale) return;
            router.replace({ ...router, locale });
        },
        [router]
    );

    return { 
        locale: router.locale || 'en', 
        switchLocale, 
        messages: flattenedMessages 
    };
};

关键说明

  • Next.js的defaultLocale仅在无匹配locale(无路径前缀且浏览器语言不匹配)时生效,无法覆盖浏览器语言自动匹配逻辑,因此必须手动干预。
  • 使用router.replace而非push,避免历史记录中堆积多余的重定向条目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:20:59