解决在同一个应用程序中拥有多个React副本的问题

问题描述 投票:0回答:6

我正在本地开发一个 React 模块。为此,我使用

npm link
链接我的模块。 模块已成功导入,但模块内部的挂钩失败。它抛出以下错误:

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

检查 React 文档 中的建议,我可以确认我的应用程序正在使用 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

这个问题充满了建议,但令人困惑。我该如何解决?

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

javascript reactjs npm webpack package.json
6个回答
32
投票

在您正在开发的模块中,将冲突的包添加到

peerDependencies
(并将它们从
dependencies
devDependencies
中删除):

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

在模块中执行

npm install

现在将

react
react-dom
添加到 你的模块 的 webpack 配置中,作为
externals
。这些包不应包含在模块的捆绑包中(使用该模块的应用程序将提供它们):

// 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 :)

19
投票

react
中添加
react-dom
peerDependencies
作为
package.json
对我来说不起作用。

我必须向 webpack 配置文件添加一个别名:

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

6
投票

作为对另一条评论的回应,仅仅将 React 移至对等依赖项并不能充分解决所有情况下的问题。我会直接回复该评论,但 StackOverflow 需要更高的声誉才能回复错误答案,而不是发布错误答案。

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

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

该文章的作者正在尝试调试 Create-React-App 应用程序。虽然 CRA 在底层使用 webpack,但您无法直接访问 webpack.config,因此作者必须执行一些解决方法才能做到这一点。如果您不使用 CRA,而只是使用普通 Webpack,那么您可以考虑使用 webpack.config 的resolve.alias 部分来确保没有 React 的重复副本(请参阅:https://blog.maximeheckel.com/帖子/重复依赖项-npm-link/


0
投票

链接的包带有其

node_modules
文件夹。一个快速临时的解决方案是在根
node_modules
文件夹中找到链接的包,然后从链接的包中删除
node_modules
文件夹。

-- node_modules 
  -- linked-package 
    -- node_modules <-------

当您只是链接以快速检查某些内容时,这可能是最简单的。


-1
投票

我尝试使用

peerDependencies
并删除
devDependencies
,但失败了。

事实证明,我正在处理的库的父文件夹之一中有一个

node_modules
文件夹,并且从那里加载了 React 的重复版本,而不是尝试使用 React 库的工具。

我没有编辑

devDependencies
来删除 React,而是编写了一个小脚本来从
peerDependencies
文件夹中删除
node_modules
中的所有内容。

npm view --json=true . peerDependencies | jq -r 'keys | .[] |  @text' | while read dep; do  rm -r ./node_modules/${dep} && echo Removed ${dep}; done

-2
投票

就我而言,我还缺少几个文件中的

import React from 'react'
检查这个

© www.soinside.com 2019 - 2024. All rights reserved.