react-intl v4升级`IntlProvider`未找到阻止组件在使用`injectIntl​​`包装器时显示

Posted

技术标签:

【中文标题】react-intl v4升级`IntlProvider`未找到阻止组件在使用`injectIntl​​`包装器时显示【英文标题】:react-intl v4 upgrade `IntlProvider` not found preventing component from displaying when using `injectIntl` wrapper 【发布时间】:2020-08-24 02:37:16 【问题描述】:

我正在尝试从 react-intl v 2.3.0 升级到 4.5.1。自升级以来,我在injectIntl HOC 周围遇到了一些问题。我在 monorepo 中有一个共享组件库,它被导入到不同的功能中(在 repo 的单独部分中组合了导入的共享组件和本地唯一组件)。但是,我的 IntlProvider 存在于我的共享组件库中,我们导入了一个名为 AppShell 的组件,其中包含任何需要的提供程序(包括 intl),这些提供程序封装了每个功能的顶层。

我遵循了关于 formatjs repo 上的问题的建议,并从我的共享组件库中删除了 react-intl 版本。这解决了我的大部分问题,但有一些警告。

注意,以下所有示例均使用带有 react-intl 版本 4.5.1 的功能文件夹,以及未安装 react-intl 版本的共享组件库

修复尝试 1

如果我尝试使用来自react-intlinjectIntl HOC,该组件将不会在页面上呈现,并且我收到以下错误:

代码示例(AppShell 包装组件位于顶层ReactDOM.render 函数中):

import  FormattedMessage, injectIntl  from 'react-intl';

// shared component library
import  Alert  from '@shared/components/alert';
// component custom to feature, also can contain shared components
import WorkspaceListContainer from './workspaceListContainer';
import messages from './messages';

export class AppLifecycleMenu extends Component 
  render() 
    const deleteAlertTitle = this.props.intl.formatMessage(
      messages.deleteAlertTitle,
       alertName: name 
    );

    return (
        <Fragment>
            <WorkspaceListContainer />
            <Alert
                title=deleteAlertTitle
                okButtonText=<FormattedMessage ...messages.deleteOkButton />
                cancelButtonText=<FormattedMessage ...messages.deleteCancelButton />
            />
      </Fragment>
    );
  


export default injectIntl(AppLifecycleMenu);

请注意,在我们的许多共享组件中,intl 消息可以作为 props 传递,并且一些组件被包装在它们自己的 injectIntl HOC 中以国际化默认版本的 props(如默认按钮标签)。

修复尝试 2

但是,如果我导入共享资源库中的 injectIntl 帮助程序,组件会呈现但仍显示错误消息:

injectIntl​​Helper 代码:

// only apply intl in non-test environments
export  default  Component  => process.env.NODE_ENV  ===  TEST_ENV  ?  Component  :  injectIntl(Component);

代码示例(AppShell 包装组件位于顶层ReactDOM.render 函数中):

import  FormattedMessage, injectIntl  from 'react-intl';

// shared component library
import  Alert  from '@shared/components/alert';
import injectIntl from '@shared/utilities/injectIntl';
// component custom to feature, also can contain shared components
import WorkspaceListContainer from './workspaceListContainer';
import messages from './messages';

export class DeleteWorkspaceAlert extends Component 
  render() 
    const deleteAlertTitle = this.props.intl.formatMessage(
      messages.deleteAlertTitle,
       alertName: name 
    );

    return (
        <Fragment>
            <WorkspaceListContainer />
            <Alert
                title=deleteAlertTitle
                okButtonText=<FormattedMessage ...messages.deleteOkButton />
                cancelButtonText=<FormattedMessage ...messages.deleteCancelButton />
            />
      </Fragment>
    );
  


export default injectIntl(AppLifecycleMenu);

带有 intlprovider 的组件树:

错误信息:

修复尝试 3

我还尝试在共享资源库中只安装react-intl,但这会导致以下错误消息:

环境

我已经尝试在 react-intl 中降低版本,但这个问题在 3.0 及更高版本中仍然存在

我已经尝试了不同的组合并在网上查找了几天,是否可以进行任何其他更改来消除这些错误?在版本之间添加或更新时,我缺少什么东西会跳出来吗?

【问题讨论】:

【参考方案1】:

对于遇到此问题的任何人,我的问题已通过关注/修改问题中的修复程序得到解决:https://github.com/formatjs/formatjs/issues/1620

与上面链接的问题不同,我的项目IntlProvider 存在于共享资源库中,并被导出以包装组件。因此,我从共享资源库以外的所有文件夹中删除了 react-intl 依赖项,并从那里导出了任何需要的组件。

所以我在非共享组件文件夹中的导入看起来像

import injectIntl,  FormattedMessage, FormattedDate  from '@shared/utils/intl';

在我的共享库中包含类似这样文件的组件

import  FormattedMessage  from 'react-intl;
export FormattedMessage;

问题的相关引用:

我认为 [具有多个依赖项] 使用旧版本的原因是旧的 React 上下文 API。新的 React 上下文 API 依赖于相同的引用。您的项目从不同的 node_modules 实例化反应上下文,因此上下文不是相同的引用。这也意味着您在应用程序中捆绑了两次 react-intl。

【讨论】:

以上是关于react-intl v4升级`IntlProvider`未找到阻止组件在使用`injectIntl​​`包装器时显示的主要内容,如果未能解决你的问题,请参考以下文章

吉日嘎拉C#快速开发平台V4.0到V4.2升级记

antd从v3升级到v4记录

ubuntn 内核升级到LINUX v4.11.8:

魔众博客系统 v4.2.0 SEO优化 性能升级

魔众博客系统 v4.2.0 SEO优化 性能升级

魔众博客系统 v4.5.0 模块更新优化 系统内核升级