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

Use react-i18next in class components with decorators and HOC

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

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

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

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

ReactDOM.render(
    <Provider store={store}>
        <Router history={history}>
            <I18nextProvider i18n={i18n}>
                <RootContainer />
            </I18nextProvider>
        </Router>
    </Provider>,
    $root,
);
@withNamespaces()
export default class SimpleComponent extends React.PureComponent {
    // (... component class code ...)
}

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

class SimpleComponent extends React.PureComponent {
    // (... component class code ...)
}
export default withNamespaces()(SimpleComponent);

我一定是遗漏了什么,因为我在 SSR 期间收到以下错误:

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|ssr-dev  | TypeError: Cannot read property 'wait' of null
0|ssr-dev  |     at NamespacesConsumerComponent.render (/client/node_modules/react-i18next/dist/commonjs/NamespacesConsumer.js:220:33)

问题是,如果我删除组件 class 上的 @withNamespaces() HOC,我将不再遇到此错误,但组件的 props 中没有 {t, i18n}因此无法翻译任何内容。 此外,不幸的是,错误中给定的 URL 已不存在。

正如我从文档中了解到的那样,<I18nextProvider> 应该将 {t, i18n} 值传递到组件树下,这不是我的情况。

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

我 运行 别无选择,如果您遇到过类似问题,我可以事后回顾一下。

提前致谢。

对于任何想知道的人,我通过包装 <RootContainer> child 而不是将 <RootContainer> 本身包装在渲染器方法中来让它工作,这给我留下了如下内容:

  • 渲染器
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 是一个 fully-fledged React 组件(准确地说是 PureComponent)。也许它与渲染链有关,不确定,但它仍然按预期方式工作。

我通过这样做设法在 class 中使用了最新版本的 react-i18next :

import { withTranslation } from 'react-i18next';

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

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