【问题标题】:Solve having more than one copy of React in the same app解决在同一个应用程序中拥有多个 React 副本的问题
【发布时间】:2021-06-03 21:28:37
【问题描述】:

我正在本地开发一个 React 模块。为此,我使用npm link 链接我的模块。 模块已成功导入,但模块内部的钩子失败。它抛出以下错误:

无效的挂钩调用。 Hooks 只能在 a 的主体内部调用 功能组件。这可能发生在以下情况之一 原因:1. 你可能有不匹配的 React 版本和 渲染器(例如 React DOM) 2. 你可能违反了 Hooks 3. 你可能在同一个应用程序中拥有多个 React 副本 请参阅https://reactjs.org/link/invalid-hook-call 以获取有关如何操作的提示 调试并修复此问题。

查看React docs 的建议,我可以确认我的应用正在使用重复版本的 React,因为以下代码返回 false:

// node_modules/mymodule/src/index.js
export { default as ReactFromModule } from 'react'
// src/index.js
import React from 'react'
import { ReactFromModule } from 'mymodule'
console.log(React === ReactFromModule) //false

This issue 充满了建议,但它们令人困惑。我该如何解决?

注意:我没有破坏钩子规则,只有从应用程序导入模块时才会出现错误。

【问题讨论】:

标签: javascript reactjs npm webpack package.json


【解决方案1】:

在您正在开发的模块中,将冲突的包添加到peerDependencies(并从dependenciesdevDependencies 中删除它们):

  // package.json
  "peerDependencies": {
    "react": "16.13.1",
    "react-dom": "16.13.1"
  },

在你的模块中执行npm install

现在将它们作为externals 添加到您的模块 的webpack 配置中。这些包不应该包含在模块的捆绑包中(使用模块的应用会提供它们):

// webpack.config.js
module.exports = {
    /*
    rest of config...
    */
    output: {
        filename: "index.js",
        pathinfo: false,
        libraryTarget: 'umd', // In my case, I use libraryTarget as 'umd'. Not sure if relevant
    },
    externals: {
        // Use external version of React
        "react": {
            "commonjs": "react",
            "commonjs2": "react",
            "amd": "react",
            "root": "React"
        },
        "react-dom": {
            "commonjs": "react-dom",
            "commonjs2": "react-dom",
            "amd": "react-dom",
            "root": "ReactDOM"
        }
    },
};

然后,在构建模块之后,在您的应用程序中,您可以检查两个版本现在是否相同:

// node_modules/mymodule/src/index.js
export { default as ReactFromModule } from 'react'
// src/index.js
import React from 'react'
import { ReactFromModule } from 'mymodule'
console.log(React === ReactFromModule) // true :)

【讨论】:

  • externals: { react: 'react' } — 为我工作
【解决方案2】:

回应另一条评论,仅将 React 移至 peerDependencies 并不能在所有情况下都充分解决问题。我会直接回复该评论,但 StackOverflow 需要更多声誉才能回复错误答案而不是发布错误答案。

我有一个使用 Webpack 构建的共享 React 组件模块并且遇到了同样的问题。我在下面的评论中概述了一个可能的修复,它需要修改 peerDependencies 并以类似于 mtkopone 共享的答案的方式使用 npm 链接。 https://github.com/facebook/react/issues/13991#issuecomment-841509933

我的解决方案有点老套,不建议长期使用。如果您使用的是 Webpack(您将此问题标记为),本文可能会详细介绍更永久的解决方案 (https://medium.com/codex/duplicate-copy-of-react-errors-when-using-npm-link-e5011de0995d)。我还没有尝试过,但作者似乎已经尝试了所有(不正确的)解决方案,并且在尝试构建共享组件库时也遇到了钩子问题。

那篇文章的作者正在尝试调试一个 Create-React-App 应用程序。虽然 CRA 在后台使用 webpack,但您无法直接访问 webpack.config,因此作者必须执行一些变通方法才能这样做。如果你没有使用 CRA,而只是使用普通的 Webpack,那么你可以考虑使用 webpack.config 的 resolve.alias 部分来确保没有 React 的重复副本(参见:https://blog.maximeheckel.com/posts/duplicate-dependencies-npm-link/

【讨论】:

  • 仅链接的答案通常是 Stack Overflow 上的 frowned upon。随着时间的推移,链接可能会萎缩并变得不可用,这意味着您的答案将来对用户毫无用处。如果您可以在实际帖子中提供答案的一般详细信息,并引用您的链接作为参考,那将是最好的。
  • 我不明白我的回答是“仅链接”,除非我写的四段文字在您的浏览器中显示为空白。
  • 您的四段文字仅指您链接的文章/来源中提到的内容。如果不访问这些站点,就不可能实施您的建议。因此,当这些链接断开时,您的答案将变得毫无用处。
  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
【解决方案3】:

package.json 中将reactreact-dom 添加为peerDependencies 对我不起作用。

我不得不为 webpack 配置文件添加一个别名:

// webpack.config.js
resolve: {
  alias: {
    react: path.resolve('./node_modules/react'),
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 2014-05-29
    • 1970-01-01
    • 2016-03-10
    相关资源
    最近更新 更多