拥有多个 React 实例意味着什么?

Mat*_*ell 7 dependency-management npm typescript reactjs

对于上下文:我在我的 React 应用程序中遇到了一个问题(使用npm+ Create React App + TypeScript),应用程序中似乎有多个 React 副本。这是基于React 文档中给出的诊断片段,您可以在其中进行测试window.React1 === window.React2

这个问题并不要求解决这个问题(我将单独调查)。相反,我想知道拥有库的副本意味着什么。它最终如何作为 CRA 生成的大捆绑脚本的一部分传递到浏览器,以及当我import React from 'react'在源代码中编写时选择哪个副本?重复的库是如何发生的,为什么npm允许这种情况发生?

答案可能是,“去了解 JS 包管理和捆绑是如何工作的”,这可能非常合理,但如果有人有任何具体的答案并指向更多学习资源,我将非常感激。TIA。

Nit*_*Nit 12

首先,让我们清楚地说明重复库在这种情况下的含义。如果您要解压捆绑的项目,您可能会发现 React 的多个版本,例如 16 和 17。在接下来的讨论中,请记住这是一个很好的框架。

\n

虽然大多数时候,这种重复是错误的,但在某些情况下这可能是可取的。在讨论您的具体案例之前,让我们先介绍一下这一点。

\n

一个很好的例子就是大型分布式开发团队使用类似于微前端架构的东西大型分布式开发团队。简而言之,两个团队可能负责页面的两个不同部分,并具有自己的一组依赖项,而不影响对方:

\n
 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n \xe2\x94\x82          Webpage          \xe2\x94\x82\n \xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x82\n \xe2\x94\x82 \xe2\x94\x82 React 16 \xe2\x94\x82 \xe2\x94\x82 React 17 \xe2\x94\x82 \xe2\x94\x82\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x82\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

虽然这看起来像是浪费空间,但开发团队在这里做出了权衡:他们的页面负载稍大,但减少了团队间版本同步的需要。也许一个团队已准备好使用最新版本,但另一个团队仍需要完成工作才能准备好更新。另一个很好的例子是遗留代码 \xe2\x80\x94 您可能拥有运行良好的代码,但没有维护,因此您选择只要它可以运行就按原样发布:

\n
 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n \xe2\x94\x82           Webpage            \xe2\x94\x82\n \xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x82\n \xe2\x94\x82 \xe2\x94\x82 Angular 1 \xe2\x94\x82 \xe2\x94\x82 Angular 10 \xe2\x94\x82 \xe2\x94\x82\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x82\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

希望上面的内容说明了为什么包管理器允许这样的设置:它们可能是可取的,并且在某些情况下非常有益。

\n

设置的方式与项目设置一样广泛,但上述方法之一是拥有某种子项目,每个子项目都有自己的package.json

\n
project\n\xe2\x94\x9c\xe2\x94\x80 package.json\n\xe2\x94\x9c\xe2\x94\x80 one subproject\n\xe2\x94\x82  \xe2\x94\x94\xe2\x94\x80 package.json\n\xe2\x94\x94\xe2\x94\x80 another subproject\n   \xe2\x94\x94\xe2\x94\x80 package.json\n
Run Code Online (Sandbox Code Playgroud)\n

在上述情况下,导入 inone subproject将设置为由package.json该文件夹中的 解析,导入 inanother subproject将设置为由其 解析package.json。配置模块解析的一种常见方法是通过Webpackresolve配置,但其他方法当然也是可能的。

\n

希望上面的内容解释了为什么这是可能的,以及一些关于何时可以考虑这样做的提示。

\n

正如之前提到的,大多数时候这是一个错误。大多数用户并不是故意这样做的,并且包含具有微小差异的相同库(例如 React 17.0.0 和 React 17.0.1)并不是他们想要做的。对于常见用例,上述两者实际上应该可以互换。

\n

有多种方法可以解决此问题,但最常见的一种是错误配置的对等依赖项。对等依赖是库、组件包等指定它们所依赖的内容,同时允许共享依赖的一种方式。一个常见的例子是一个 UI 组件库,它支持任何 React 版本,只要它比 React 16 更新。如果您的项目使用 React 17,那么您可以愉快地引入该组件库并拥有单一版本代码库中的 React。

\n

当库作者(无意中)将 React 16 的依赖项配置为常规依赖项而不是对等依赖项时,就会发生此错误。在这种情况下,作者本质上是说该库需要 React 16 并且不允许其他任何内容,最终您将安装两个版本的 React。

\n

以上所有内容都是非常粗略的,并且涉及了很多细节,但希望这能让您深入了解您正在解决的问题。

\n