解决未升级到next-i18next时因Layout.tsx导致的在切换语言时出现的react-i18next hydration错误
在语言切换之间刷新或重定向到页面时,我遇到了一个 react-i18next 水合错误。
水合失败,因为服务器渲染的文本与客户端不匹配。
因此,这个树结构将在客户端重新生成。若使用了SSR的客户端组件:
然而,将其升级到 next-18next 的 推荐解决方案 对我不起作用。它需要 appWithTranslation(App) 的封装,我们由于 layout.tsx 的做法而无法提供。
据Google指出:
appWithTranslation HOC与 App Router的 layout.tsx不兼容,因为 Server Components 不以相同的方式支持HOCs。相反,next-i18next (v16+) 或像next-intl这样的库使用不同的模式。
由于基于布局的 layout.tsx 方式,我们的App组件看起来像:
const App = (props: {page: string}) => { ... }
而不是:
const App = ({ Component, pageProps }: AppProps) => { ... }
这会导致与 appWithTranslation 相关的错误。
在不升级到 next-18next 的情况下,有没有办法消除这个错误?
当前的 initTranslations 钩子:
export default async function initTranslations(
locale: any,
namespaces: string[],
i18nInstance?: any,
) {
i18nInstance = i18nInstance || createInstance();
i18nInstance.use(initReactI18next);
i18nInstance.use(LanguageDetector);
await i18nInstance.init({
lng: locale,
detection: options,
resources,
fallbackLng: i18nConfig.defaultLocale,
supportedLngs: i18nConfig.locales,
defaultNS: namespaces[0],
fallbackNS: namespaces[0],
ns: namespaces,
preload: resources ? [] : i18nConfig.locales
});
return {
i18n: i18nInstance,
resources: i18nInstance.services.resourceStore.data,
t: i18nInstance.t
};
接着我们有一个 TranslationsProvider 组件:
export default function TranslationsProvider({
children,
locale,
namespaces,
}: Readonly<{
children: React.ReactNode;
locale: string;
namespaces: string[];
}>) {
const i18n = createInstance();
initTranslations(locale, namespaces, i18n);
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
}
例如,主页按如下方式使用它:
export default function Home() {
const params = useParams<{ locale: string}>();
return (
<div>
<TranslationsProvider
namespaces={i18nNamespaces}
locale={params.locale}>
<App page="" />
</TranslationsProvider>
</div>
);
}
解决方案
我通过添加以下副作用(effect),在浏览器就绪时(即完成水合状态)设置一个变量,这在第一次初始化的effect [] 时发生。
const [isHydrated, setIsHydrated] = useState(false);
useEffect(() => {
setIsHydrated(true);
}, []);
// In Render code
if (!isHydrated) return null;
return(..); // Normal render after check
这可以把它做成一个钩子。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。