【问题标题】:Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestryReact Intl - 找不到所需的“intl”对象。 <IntlProvider> 需要存在于组件祖先中
【发布时间】:2019-12-25 08:56:11
【问题描述】:

在使用 React Intl 进行本地化时,我们不断通过 Airbreak 从我们的 React 应用程序中收到随机错误消息。

错误信息

Invariant Violation: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.

我们的应用程序非常小。我们有三个页面,其中一个页面嵌入了多个模式对话框,然后可能由用户打开。我们无法将此问题精确定位到确切的浏览器、版本或代码点。

我们试图深入研究错误消息并找到确切原因,但没有运气。模态对话框作为主组件的子组件存在,并在渲染父组件时嵌入。

我们的 main.js 渲染使用 IntlProvider 包装:

render() {
    return (
        <ErrorBoundary>
            <IntlProvider locale={language} messages={messages[language]}>
                <Router> 
                    <Route render={({location}) => (
                        <div id="site-container">
                                     ...

ErrorBoundary 是 Airbrake。 IntlProvider 获取语言环境和翻译的字符串。

父组件已注入 Intl:

Page.propTypes = {
intl: intlShape.isRequired
};

export default injectIntl(Page);

IntlProvider 的用法与文档中描述的一样,但我们是否在这里遗漏了什么?这个错误的原因是什么?某些对话框没有获得为其提供的 intl?

我们不应该遇到这些错误。如果确实如此,它似乎会导致任何页面加载完全崩溃。

【问题讨论】:

  • 从您提供的代码中很难说,但一种猜测是您没有在使用 intl 属性的每个组件中注入 intl。
  • 我们没有使用 injectIntl​​ 的唯一地方是应该嵌入到父渲染函数中的子组件,例如“”。 MessageDialog 组件(子组件)是否也应该使用 InjectIntl​​?我相信我尝试过一次,它崩溃了,因为父母已经注入了它。
  • 如果你在你的子组件中使用intl prop,你可能需要显式地将它注入那里,或者只是从父组件传递它。 Afaik,react-intl 不会自动将注入的 intl 传递给孩子。
  • 我相信我已经作为父母将 {... this.props} 传递给所有已经包含 intl 的子组件。
  • 好吧,我发现一个组件在我们的 Header 组件中被调用,它没有使用 injectIntl​​ 或将 props 作为父级传递给它。该组件包含在所有视图中,它是我们的语言选择链接容器。如果这是原因,很奇怪我们在开发过程中从未发现过它,而且它似乎只是在奇怪的位置非常随机地发生(我们还可以跟踪这些错误发生的 URL,并且似乎发生在所有三个页面上)

标签: reactjs intl


【解决方案1】:

为我解决此问题的解决方案是确保每次需要在开玩笑测试中安装组件时都使用 i18n 安装测试文件。这是一个例子:

it('set the value to 4 if changed value is not a number', () => {
  const wrapper = mountWithTestFileI18N(<Component {...props} />);
  wrapper.find('.form-input').simulate('change', { target: { value: 'tt' } });
  wrapper.find('.form-input').simulate('blur');

  expect(wrapper.find('.form-input').props().value).toBe(4);
});

您需要确保在每次开玩笑测试时都遵循这个安装公式。你应该在你的 jestsetup.js 文件中有你的挂载函数。这是一个例子:

function mountWithIntl(node, intlKeys, formatKeys, { context, childContextTypes } = 
    {}) {
  const { intl } = getIntlContext(intlKeys, formatKeys);
  return mount(nodeWithIntlProp(node, intl), {
    context: { ...context, intl },
    childContextTypes: { ...childContextTypes, intl: intlShape },
  });
}

【讨论】:

    【解决方案2】:

    对我来说,原来我的 ErrorBoundaries 超出了 IntlProvider 的范围

        <Router>
            <SentryBoundary>
             <IntlProvider locale={this.state.lang} messages={localeData[this.state.lang]}>
                <Navbar lang={this.state.lang} changeLang={this.changeLang} />
                <div>
                    <Route exact path="/" render={(props) => <Start{...props} />}/>
                </div>
             </IntlProvider>
            </SentryBoundary>
        </Router>
    

    我所要做的就是将边界移到 IntlProvider 的内部

        <Router>
          <IntlProvider locale={this.state.lang} messages={localeData[this.state.lang]}>
            <SentryBoundary>
                <Navbar lang={this.state.lang} changeLang={this.changeLang} />
                <div>
                    <Route exact path="/" render={(props) => <Start{...props} />}/>
                </div>
            </SentryBoundary>
          </IntlProvider>
        </Router>
    

    【讨论】:

      猜你喜欢
      • 2021-10-03
      • 2020-11-23
      • 2021-06-02
      • 2017-06-03
      • 1970-01-01
      • 2020-08-24
      • 2015-06-25
      • 2019-04-12
      • 2018-05-26
      相关资源
      最近更新 更多