Reactjs 使用React-i18next水合SSR React App会导致闪烁

Reactjs 使用React-i18next水合SSR React App会导致闪烁,reactjs,server-side-rendering,react-i18next,Reactjs,Server Side Rendering,React I18next,很长一段时间以来,我一直试图让SSR与react-i18next一起工作,文档有点缺乏,因此我将我能从其他回购协议和他们的协议中拼凑出的东西拼凑起来 我让服务器端工作,其中我: 安装express,调用适当的中间件,获取适当的区域设置: 获取给定请求的应用程序的DOM表示形式: 当我curl时,这非常有效http://localhost:3000/我通过加载/替换的翻译获得了正确的DOM 我遇到的问题是水合作用 我尝试将useSSR与suspend一起使用,但似乎无法使其正常工作。但我觉得这基本

很长一段时间以来,我一直试图让SSR与
react-i18next
一起工作,文档有点缺乏,因此我将我能从其他回购协议和他们的协议中拼凑出的东西拼凑起来

我让服务器端工作,其中我:

  • 安装express,调用适当的中间件,获取适当的区域设置:
  • 获取给定请求的应用程序的DOM表示形式:
  • 当我
    curl时,这非常有效http://localhost:3000/
    我通过加载/替换的翻译获得了正确的DOM

    我遇到的问题是水合作用

    我尝试将
    useSSR
    suspend
    一起使用,但似乎无法使其正常工作。但我觉得这基本上会有相同的问题:
    i18n
    需要先用语言初始化,然后才能使用应用程序。正确(?)

    我试图通过等待
    客户端
    i18n
    实例在应用程序水合之前初始化,来模拟与
    useSSR
    相同的事情:

    // client i18n.js
    import i18n from 'i18next';
    import { initReactI18next } from 'react-i18next';
    import Backend from 'i18next-http-backend';
    import LanguageDetector from 'i18next-browser-languagedetector';
    
    i18n
      .use(initReactI18next)
      .use(Backend)
      .use(LanguageDetector);
    
    const i18nInit = () => {
      return new Promise(resolve => {
        // @todo: shim in moment locale here
        i18n.init(options, () => resolve(i18n));
      });
    };
    
    export default i18nInit;
    
    但这会导致类似的,但不是无样式的闪烁,而是返回
    null
    的白色屏幕


    这里有我遗漏的概念吗?还是我在做一些不正常的事?如何实现从服务器提供的DOM+样式到客户端提供的包含翻译的DOM+样式的无缝转换?

    我已尝试重现您的问题。在您提到的步骤中:

    我试图通过等待客户端i18n实例初始化,然后再对应用程序进行水合处理,来模拟与useSSR相同的情况:

    // client i18n.js
    import i18n from 'i18next';
    import { initReactI18next } from 'react-i18next';
    import Backend from 'i18next-http-backend';
    import LanguageDetector from 'i18next-browser-languagedetector';
    
    i18n
      .use(initReactI18next)
      .use(Backend)
      .use(LanguageDetector);
    
    const i18nInit = () => {
      return new Promise(resolve => {
        // @todo: shim in moment locale here
        i18n.init(options, () => resolve(i18n));
      });
    };
    
    export default i18nInit;
    
    在这一步中,我发现SSR结果与CSR结果不同:

    这是因为我的语言是zh TW,服务器端没有提供“fallbackLng”

    我像
    i18n.js
    那样添加了这一行,并解决了这个问题

    //server.js
    i18n
    .使用(后端)
    .use(i18nextMiddleware.LanguageDetector)
    .init(
    {
    调试:错误,
    预加载:['en','de'],
    撤退:“恩”//没有像恩-美、德-德那样的特定于地区的本地人
    //在整个应用程序中使用通用名称空间
    ns:[“翻译”],
    defaultNS:“翻译”,
    对,,
    是的,
    插值:{
    escapeValue:false,//不需要react!!
    formatSeparator:',',
    格式:(值、格式、液化天然气)=>{
    if(format=='uppercase')返回值.toUpperCase();
    返回值;
    },
    },
    反应:{
    useSup悬念:false,//{
    使用ssr(window.initialI18nStore,window.initialLanguage);
    返回(
    );
    }
    
    一切正常

    const initialI18nStore = {};
    req.i18n.languages.forEach(l => {
      initialI18nStore[l] = req.i18n.services.resourceStore.data[l];
    });
    const initialLanguage = req.i18n.language;
    
    content = content.replace(
    /<head>/,
        `<head>
            <script>
            window.initialI18nStore = "${JSON.stringify(initialI18nStore)}";
            window.initialLanguage = "${initialLanguage.slice(0, 2)}";
        </script>`,
    );
    
    // client i18n.js
    import i18n from 'i18next';
    import { initReactI18next } from 'react-i18next';
    import Backend from 'i18next-http-backend';
    import LanguageDetector from 'i18next-browser-languagedetector';
    
    i18n
      .use(initReactI18next)
      .use(Backend)
      .use(LanguageDetector);
    
    const i18nInit = () => {
      return new Promise(resolve => {
        // @todo: shim in moment locale here
        i18n.init(options, () => resolve(i18n));
      });
    };
    
    export default i18nInit;
    
    // client index.js
    const renderApp = async () => {
      let i18n = await i18ninit();
      if (window.initialI18nStore) {
        i18n.services.resourceStore.data = window.initialI18nStore;
      }
      hydrate(<BaseApp />, document.getElementById('root'));
    };
    
    renderApp();
    
    const BaseApp = () => {
        const [render, setRender] = useState(false);
        useEffect( () => {
            await initI18();
            i18n.services.resourceStore.data = INITIALI18NSTORE;
            setRender(true);
        }, [])
        if(!render) return null;
        return <App />
    }