使用next-intl出现hydration错误,请求排查配置问题
Next-intl 配置问题:Hydration 错误修复
问题描述
首次使用next-intl库,配置后出现以下hydration错误:
In HTML, cannot be a child of , This will cause a hydration error
该错误仅在访问NotFound页面或返回旧页面时触发。
项目文件夹结构:
- 根目录下
app文件夹,包含:layout/RootLayout.tsx(根布局文件)- 根级
not-found.tsx [locale]本地化路由目录,内部有not-found.tsx(复用根级NotFound页面)
错误原因
核心问题是NotFound页面手动嵌套了RootLayout。在Next.js App Router机制中,not-found.tsx作为错误页面会自动被根布局RootLayout包裹,无需手动引入。当你在NotFoundPage中再次渲染RootLayout时,页面会生成双重<html>结构——外层RootLayout的<body>内部又嵌套了一个完整的<html>标签,直接触发hydration错误。
解决方案
1. 修改根级not-found.tsx代码
移除RootLayout的嵌套,只保留页面内容:
import React from 'react'; import { useTranslations } from 'next-intl'; const NotFoundPage = () => { const language = useTranslations('notFound'); return ( <div className='not-found-page'> <div className='not-found-container'> <h1>{language('title')}</h1> <h2>{language('content')}</h2> <p>{language('description')}</p> </div> </div> ); }; export default NotFoundPage;
2. 保留本地化路由的not-found.tsx内容
[locale]/not-found.tsx无需修改,继续复用根级NotFound页面即可:
export { default } from '@/app/not-found';
3. 确认RootLayout的正确性
你的RootLayout.tsx代码本身是正确的,它会自动作为所有页面(包括NotFound、Error等特殊页面)的外层布局,无需在子页面中手动引入:
import React from 'react'; import localFont from 'next/font/local'; import { NextIntlClientProvider } from 'next-intl'; import { getMessages } from 'next-intl/server'; import { ReactNode } from 'react'; import { ToastProvider } from '@/providers/toaster-provider'; import BackToTopProvider from '@/providers/back-to-top-provider'; import { AuthProvider } from '@/contexts/AuthContext'; import type { Metadata } from 'next'; const lora = localFont({ src: '../fonts/Lora.ttf', variable: '--font-lora', weight: '400 500 600 700 800', }); const notoSans = localFont({ src: '../fonts/NotoSansSC.ttf', variable: '--font-noto-sans', weight: '400 500 600 700 800', }); export const metadata: Metadata = { title: 'Create Next App', description: 'Generated by create next app', }; type Props = { children: ReactNode; locale: string; }; export default async function RootLayout({ children, locale }: Props) { const messages = await getMessages({ locale }); return ( <html lang={locale}> <body className={`${lora.variable} ${notoSans.variable}`}> <NextIntlClientProvider messages={messages}> <AuthProvider> <BackToTopProvider> <ToastProvider /> {children} </BackToTopProvider> </AuthProvider> </NextIntlClientProvider> </body> </html> ); }
后续验证
- 重启开发服务器,清理缓存(可执行
npm run dev -- --clean) - 访问NotFound页面,确认hydration错误消失
- 检查其他页面是否存在类似手动嵌套RootLayout的情况,避免重复触发错误
内容的提问来源于stack exchange,提问作者Khuong Viet Tai
相关产品推荐
相关产品推荐

