在带有装饰器和 HOC 的类组件中使用 react-i18next

Posted

技术标签:

【中文标题】在带有装饰器和 HOC 的类组件中使用 react-i18next【英文标题】:Use react-i18next in class components with decorators and HOC 【发布时间】:2019-10-21 11:05:41 【问题描述】:

我正在尝试在我的 React 项目中实现 i18n,该项目也在 react-i18next 的帮助下使用 Redux。

在这个项目中,我们使用带有装饰器的类组件。

最初,我想尝试react-i18next v10,但由于它依赖于钩子并且我不能在类组件中使用它们,所以对我来说这是不可能的。

回到旧版 v9,我按照分步指南 (https://react.i18next.com/legacy-v9/step-by-step-guide) 执行了以下步骤:

创建了带有翻译的i18n.js 配置文件 用i18nextProvider 包裹了我的根容器
ReactDOM.render(
    <Provider store=store>
        <Router history=history>
            <I18nextProvider i18n=i18n>
                <RootContainer />
            </I18nextProvider>
        </Router>
    </Provider>,
    $root,
);
使用withNamespaces() HOC 包装了一个简单组件,它是RootContainer 的子组件,但使用了装饰器语法
@withNamespaces()
export default class SimpleComponent extends React.PureComponent 
    // (... component class code ...)

没有装饰器的情况等同于以下内容:

class SimpleComponent extends React.PureComponent 
    // (... component class code ...)

export default withNamespaces()(SimpleComponent);

我一定是遗漏了一些东西,因为我在 s-s-r 期间收到以下错误:

react-i18next:: You will need pass in an i18next instance either by props, using I18nextProvider or by using i18nextReactModule. Learn more https://react.i18next.com/components/overview#getting-the-i-18-n-function-into-the-flow
0|s-s-r-dev  | TypeError: Cannot read property 'wait' of null
0|s-s-r-dev  |     at NamespacesConsumerComponent.render (/client/node_modules/react-i18next/dist/commonjs/NamespacesConsumer.js:220:33)

问题是,如果我删除组件类上的@withNamespaces() HOC,我将不再出现此错误,但是组件的道具中没有t, i18n,因此无法翻译任何内容。 此外,不幸的是,错误中的给定 URL 不再存在。

正如我从文档中了解到的,&lt;I18nextProvider&gt; 应该将t, i18n 值向下传递到组件树,而我的情况并非如此。

我发现自己陷入了无法使用 v10(我们有很多组件,目前我不能将它们全部重构为功能组件)和无法使 v9 正常工作之间。

我的选择已经不多了,如果你遇到过类似的问题,我可以使用后见之明。

提前致谢。

【问题讨论】:

【参考方案1】:

对于任何想知道的人,我通过在渲染器方法中包装 &lt;RootContainer&gt; 子而不是包装 &lt;RootContainer&gt; 本身来使其工作,这给我留下了如下内容:

渲染器
ReactDOM.render(
    <Provider store=store>
        <Router history=history>
            <RootContainer />
        </Router>
    </Provider>,
    $root,
);
根容器
import i18n from "../core/translations/i18n";
import I18nextProvider from "react-i18next";

@connectWithStore(mapStateToProps, mapActionsToProps)
export default class RootContainer extends React.PureComponent 
    // (... class code ...)

    render 
        return (
            <I18nextProvider i18n=i18n>
                <div>
                    <SimpleComponent/>
                </div>
            </I18nextProvider>
        );
    

简单元素
import withNamespaces from "react-i18next";

@withNamespaces()
export default class SimpleComponent extends React.PureComponent 
    // (... class code ...)

    componentDidMount() 
        // Successfully logging the values below
        console.warn("Got i18n props?", 
            t: this.props.t,
            i18n: this.props.i18n,
        );
    

唯一的区别是我的渲染器是一个函数,而不是一个组件本身,而RootContainer 是一个成熟的 React 组件(准确地说是 PureComponent)。也许它与渲染链接有关,不确定,但它仍然可以按预期方式工作。

【讨论】:

【参考方案2】:

我通过这样做在课堂上使用了最新版本的 react-i18next:

import  withTranslation  from 'react-i18next';

class RootContainer extends React.Component 
  constructor(props) 
    super(props);
  

  render() 
   <span>this.props.t('Home')</span>
  

【讨论】:

那么导入 withTranslation 是为了什么?

以上是关于在带有装饰器和 HOC 的类组件中使用 react-i18next的主要内容,如果未能解决你的问题,请参考以下文章

React Redux 使用带有连接组件的 HOC

React: 高阶组件(HOC)

React HOC 返回一个匿名的 _class

React/Reflux:使用装饰器将带有 mixin 的类转换为 ES6

在 React 中定义和导出 HOC

是否可以通过使用 HOC(高阶组件)在类组件中使用 React Hooks?