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

使用next-i18next时Next.js页面布局重复渲染问题求助

Next-i18next 布局重复渲染问题解决方案

问题描述

使用next-i18next时,已按规范完成实现,但带有getStaticProps的页面布局组件总是重复渲染,需要阻止该现象。我创建了withStaticTranslations.ts工具函数并在页面中使用,但该翻译逻辑无法在_app.tsx或全局Layout组件中生效。

现有代码

withStaticTranslations.ts

import { GetStaticProps, GetStaticPropsContext, GetStaticPropsResult } from 'next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';

type WithStaticTranslationsOptions = {
    namespaces?: string[];
};

export const withStaticTranslations = (
    getStaticPropsFunc?: GetStaticProps,
    { namespaces = ['common'] }: WithStaticTranslationsOptions = {}
): GetStaticProps => {
    return async (context: GetStaticPropsContext): Promise<GetStaticPropsResult<any>> => {
        const translations = await serverSideTranslations(context.locale || 'en', namespaces);

        if (getStaticPropsFunc) {
            const pageStaticProps = await getStaticPropsFunc(context);

            if ('props' in pageStaticProps) {
                return {
                    props: {
                        ...translations,
                        ...pageStaticProps.props,
                    },
                };
            }

            return pageStaticProps;
        }

        return { props: translations };
    };
};

页面使用示例

import type { NextPage } from 'next'
import React from "react";
import ImageSlider from "@/components/Organisms/ImageSlider";
import { withStaticTranslations } from '@/composables/withStaticTranslations';
import { GetStaticProps } from 'next';

const Home: NextPage = () => {
    return (
        <>
            <ImageSlider />
        </>
    )
}

export const getStaticProps: GetStaticProps = withStaticTranslations();

export default Home;

解决方案

方案一:用React.memo缓存Layout组件(最快见效)

布局重复渲染的核心原因是:每次页面切换时,serverSideTranslations返回的翻译对象会被视为新的props,触发Layout组件重渲染。用React.memo对Layout组件做浅比较缓存,可直接阻止无意义的重渲染。

修改Layout组件:

import React from 'react';
import { useTranslation } from 'next-i18next';

const Layout = ({ children }: { children: React.ReactNode }) => {
    const { t } = useTranslation('common');
    return (
        <div>
            <header>{t('header.title')}</header>
            {children}
        </div>
    );
};

// 仅当props真正变化时才重渲染组件
export default React.memo(Layout);

方案二:在_app.tsx中处理公共翻译,避免重复加载(性能优化)

若担心在_app.tsx中加载所有翻译影响性能,可以仅在_app.tsx中加载公共命名空间(如common),页面级命名空间由各自的getStaticProps单独加载,既避免布局重复渲染,又不会一次性加载所有翻译资源。

  1. 修改_app.tsx添加公共翻译逻辑:
import type { AppProps } from 'next/app';
import { appWithTranslation } from 'next-i18next';
import Layout from '@/components/Layout';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';

function MyApp({ Component, pageProps }: AppProps) {
    return (
        <Layout>
            <Component {...pageProps} />
        </Layout>
    );
}

// 在_app中加载公共命名空间,所有页面自动继承这些翻译props
export async function getStaticProps(context: any) {
    return {
        props: await serverSideTranslations(context.locale || 'en', ['common']),
    };
}

export default appWithTranslation(MyApp);
  1. 修改withStaticTranslations避免重复加载公共命名空间:
export const withStaticTranslations = (
    getStaticPropsFunc?: GetStaticProps,
    { namespaces = [] }: WithStaticTranslationsOptions = {} // 默认不加载common,由_app提供
): GetStaticProps => {
    return async (context: GetStaticPropsContext): Promise<GetStaticPropsResult<any>> => {
        // 仅加载页面专属的命名空间
        const translations = namespaces.length > 0 
            ? await serverSideTranslations(context.locale || 'en', namespaces)
            : {};

        if (getStaticPropsFunc) {
            const pageStaticProps = await getStaticPropsFunc(context);

            if ('props' in pageStaticProps) {
                return {
                    props: {
                        ...translations,
                        ...pageStaticProps.props,
                    },
                };
            }

            return pageStaticProps;
        }

        return { props: translations };
    };
};
  1. 页面使用时传入专属命名空间:
export const getStaticProps: GetStaticProps = withStaticTranslations(undefined, {
    namespaces: ['home'] // 仅加载home页面的专属翻译
});

方案三:稳定翻译props引用(进阶优化)

若上述方案仍有问题,可通过稳定翻译对象引用进一步优化:在withStaticTranslations中合并props时,用Object.freeze锁定对象,确保相同翻译内容不会生成新的引用。

修改withStaticTranslations的props合并逻辑:

if ('props' in pageStaticProps) {
    const mergedProps = {
        ...pageStaticProps.props,
        ...translations,
    };
    // 冻结对象避免后续修改导致引用变化
    Object.freeze(mergedProps);
    return {
        props: mergedProps,
    };
}

关键说明

  • withStaticTranslations无法直接在Layout组件中生效,因为getStaticProps是页面级生命周期函数,组件本身不能直接使用,必须通过页面或_app.tsx传递props。
  • 优先用方案一快速解决重渲染问题,再结合方案二优化性能,避免不必要的翻译资源加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:04:55