React: Hooks + React 的多个实例

创建于 2018-10-27  ·  285评论  ·  资料来源: facebook/react

来自搜索的人:请先阅读此页面。 它包含最常见的可能修复!

您要请求功能还是报告错误

增强

当前的行为是什么?

我错误地有多个 React 实例。

尝试使用钩子时,出现此错误:
hooks can only be called inside the body of a function component

这是不正确的,因为我使用的是功能组件。 我花了一段时间才找到问题的真正原因。

预期的行为是什么?

显示正确的错误信息。 也许检测到应用程序有多个 React 实例并说这可能是错误的原因。

Hooks Discussion

最有用的评论

我有同样的问题,我通过添加解决了它:

 alias: {
        react: path.resolve('./node_modules/react')
      }

到我的主应用程序的 webpack 配置中的resolve属性。

使用两个 React 副本显然是我的错误,但我同意如果错误消息更好,那就太好了。 我认为这可能类似于: https ://github.com/facebook/react/issues/2402

所有285条评论

所以只是为了澄清一下:您是从与用于渲染组件的模块不同的react模块中导入一个钩子(比如useState )?

我同意这令人困惑。 我不确定我们是否有办法知道是否有其他 React 模块正在渲染。 AFAIK 我们尝试尽可能孤立地运行 React,以便多个 React 实例可以在同一个全局上下文中工作而不会出现问题。

否则,我们可能会更新错误消息并提及这个案例,如果它不是太令人困惑的话。

是的,我比较React1 === React2 ,它是false (React1 来自 index.js,React2 来自使用钩子的文件)。 发生这种情况时,钩子会失败并显示上面的一般错误消息。

这个问题是为了提高对这种情况的认识,并可能以某种方式改进错误消息以帮助面对这种情况的人。 不过,它可能非常有优势。

是的,我试图npm 链接我正在创建的包。 它抛出了同样的错误,因为另一个包也使用了钩子,但有自己的 React。 我必须将我的包发布到 NPM,然后直接从 NPM 导入。 这样错误就消失了,但我希望这个问题得到解决,因为发布一个包而不测试它是不好的,显然

当在一个包中定义自定义钩子并由另一个包使用时,Lerna monorepos 也会受到此影响,因为符号链接的依赖项使用它们自己的 react 副本。

我目前有一个(hacky)解决方法,使用npm-link-sharedprestart npm 脚本基本上将一个包的react依赖项替换为另一个包的符号链接,所以他们使用同一个例子。

"prestart": "npm-link-shared ./node_modules/<other package>/node_modules . react"

我有同样的问题,我通过添加解决了它:

 alias: {
        react: path.resolve('./node_modules/react')
      }

到我的主应用程序的 webpack 配置中的resolve属性。

使用两个 React 副本显然是我的错误,但我同意如果错误消息更好,那就太好了。 我认为这可能类似于: https ://github.com/facebook/react/issues/2402

@mpeyper它有效。 谢谢

@apieceofbart这对我有用。 谢谢你的建议。 👍

据我了解,当同一个包中有多个 React 副本时,就会出现这个问题。

如果两个具有自己的 React 副本的单独捆绑包在单独的 dom 元素上引导自己的 React 应用程序,这也是一个问题吗,如下所述: https ://medium.jonasbandi.net/hosting-multiple-react-applications-on-

我认为后者是一种常见的“集成”模式,例如在单水疗元框架(https://github.com/CanopyTax/single-spa)中使用。

即使使用完全相同的反应版本,我也遇到了这个问题,使用npm-link时,开发要自行发布的钩子会被破坏。 得到同样无用的hooks can only be called inside the body of a function component消息。 @apieceofbart的别名解决方案为我解决了这个问题。 非常感谢!

当我将npm link一个包添加到我的主应用程序时,这里也会出现同样的问题。 我无法让babel-plugin-module-resolver工作。
它说:
Could not find module './node_module/react'
这很烦人,因为它阻止我在发布之前在本地测试我的组件。

我通过删除"react": "^16.7.0-alpha.2"中的插入符号解决了我的问题
这是完整的评论: https ://github.com/facebook/react/issues/14454#issuecomment -449585005

我正在使用 Yarn,并通过在我的package.json强制解析来解决此问题:

  "resolutions": {
    "**/react": "16.7.0-alpha.2",
    "**/react-dom": "16.7.0-alpha.2"
  },

同样在这里!!

只是想在这里为任何可能以与我相同的方式遇到此问题的人留个便条。

我们使用react-rails gem 运行 React 和 Rails,并将组件直接渲染到 Rails 视图中。 每次推送应用程序的新版本时我都会收到此错误,因为 Turbolinks 正在从<head>中获取新的 JS 包,该包加载了一个额外的 React 实例。 解决方案是让 Turbolinks 在检测到捆绑包已更改时重新加载整个页面: https ://github.com/turbolinks/turbolinks#reloading -when-assets-change

这似乎已经为我们解决了。

我很高兴终于将 Hooks 投入生产,我们都非常感谢所有使之成为可能的人。 使用它们很有趣,并且使我的代码更短更具声明性。

提醒一下,这个问题在已发布的版本中仍然存在,同样无用的错误消息“只能在函数组件的主体内调用 Hooks”。

这是可以修复的吗? 我想随着越来越多的开发人员开始实施新功能,它可能会变得越来越普遍,并且更清晰的错误消息将在很大程度上代替彻底的“修复”。

再次感谢所有辛勤工作并祝贺发布! 这确实是一组了不起的功能。

编辑:应该仔细看看开放的 PR,刚刚发现 #14690 解决了这个问题。 谢谢@threepointone!

@taylorham提交中的链接尚未指向任何内容。 我会等待它,但这是自从在链接的 _(截至npm link )_ 包中使用钩子以来我一直遇到的问题,并且如果不发布就无法在本地使用它。
在查看了几个问题后,我认为这是将组件编译为类的 react-hot-loader 的问题,但即使他们发布了支持 Hook 的版本,它仍然以同样的方式失败。
我尝试了很多不同的黑客,但没有运气。 我不知道为什么大家还没有被这个问题打动🧐

@dotlouis是的,到目前为止,这只是一条更新的错误消息,问题本身仍然很痛苦。

唯一对我有用的是使用"react": "link:../my-library/node_modules/react"使我正在开发的任何应用程序都依赖于库的React 实例。

  • 提议的决议都没有对我有用,我一直在尝试所有
  • 尝试安装在项目实施上下文和许多 HOC 上
  • 从一个空白项目开始就成功了
  • 我一直在寻找原因

[好的] 对我来说,更正不是关于 package.json 或其他双重反应的原因:我的应用程序顶部有一个全局 themeProvider,来自上下文。 用“useContext Hook”替换它(同时将其重写为功能组合)似乎是唯一的解决方案
也许有什么问题

<GoodOldContext iam={a class component}>
    <BrandNewHook>
             errors : Hooks can only be called inside the body of a function component #35
     </BrandnewHook>
</GooOldContext>
export withGoodOldContext.consumer(here component)

我正在开发一个组件,其中有一个使用create-react-appexample文件夹。

package.json中执行此操作为我解决了这个问题:

{
    ...
    "dependencies": {
        "my-component": "link:..",
        "react": "link:../node_modules/react",
        "react-dom": "link:../node_modules/react-dom",
        "react-scripts": "2.1.3"
    },
    ...
}

@taylorham @DylanVann感谢您的意见。 不幸的是,它仍然对我不起作用。
而且我找不到有关您使用的此link:协议的任何文档。
基本上,它说“react-spring”(另一个也使用 react 作为依赖项的部门)找不到react-dom 。 你能给我一些关于"react": "link:../some/path"的文档吗?

我也在使用链接的 UI 包,我能够解决这个问题。
您需要从 UI(链接包)导出 react renderToString。
我在链接包中创建了渲染函数。

只是为了更好的上下文 - https://github.com/facebook/react/issues/14257

谢谢@theKashey。 @gaearon似乎认为这是正常行为。 我知道 React 不应该加载两次,但是那么推荐的使用链接本地包的方法是什么?

我也遇到了 Lerna 工作区正确符号链接的问题。 这是我用来让它工作的技巧。 确保之后运行npm install

"dependencies": {
    "react-dom": "file:../common/node_modules/react-dom",
    "react": "file:../common/node_modules/react"
}

有很多方法可以解决它,而纱线分辨率通常无济于事——它与“构建工具”更相关

  • 对于 webpack 使用aliases - 只是“硬”别名,一切都像react到单个文件中
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: {
     react: path.resolve(path.join(__dirname, './node_modules/react')),
   }
import {setAliases} from 'require-control';
setAliases({
  'react': path.resolve(path.join(__dirname, './node_modules/react'))
});
  • 开玩笑用moduleNameMapper
"jest": {
    "moduleNameMapper": {
      "^react$": "<rootDir>/node_modules/$1",
    },

@theKashey感谢您的见解,当我们考虑如何完成模块解析时,这是有道理的(从底部,然后在树上),但从用户的角度来看,我觉得这不是很实用。 当我npm link一个包时,我希望它无需显式重新连接依赖项即可工作。 这使得在本地开发包非常痛苦。

这是一个基石,这就是node_modules设计的工作方式,这就是为什么您可能在两个不同的主要版本中有两个版本的Button ,并且依赖模块将轻松找到“正确的”包的版本。
这就是它应该一直工作的方式。

Node.js内部结构非常简单 - 尝试打开一个添加所有已知前缀(如node_modules )或扩展名(如jstsjson的文件

yarn pnp会这样做,并且可能会解决问题。 yarn workspaces ,它可能 _hoist_ 共享包到顶部 - 也将解决问题而不涉及任何“魔法”。

npm workspaces ? 目前不存在。

实际上,我最终将我的项目切换为使用工作区。 它无需使用分辨率即可解决此问题,并且无论如何提升/结构都是有益的。

这是一个令人头疼的问题。 我尝试了 webpack resolve.alias 设置,但它不起作用,也尝试了许多设置,但不幸的是从未真正让它工作,但这是我最终设法让它工作的方法:

这是我的文件夹结构:

项目
|
+-- 节点模块
|
+-- 构建
| |
| +-- index.js
|
+-- 示例(创建反应应用程序)
| |
| +--包.json

我不得不在示例文件夹中修改我的 package.json,基本上是根据@jmlivingston的建议从项目的“主要”node_modules 中提取反应,这是它的最终结果:

  "dependencies": {
    "react": "file:../node_modules/react",
    "react-dom": "file:../node_modules/react-dom",
    "react-scripts": "2.1.5"
  },

在那之后我跑了npm install ,然后我跑了npm link ,就成功了。

希望这可以帮助其他人并节省一些时间。

那么这个问题有什么解决办法吗? 我在这里尝试了尽可能多的建议,但没有运气。 我正在使用 create-react-app 和打字稿。 使用 React/React-dom 16.8.3。 这是我两天前创建的一个新项目,非常简单。 我正在使用 useSpring() 和 animated.div。 谢谢

@guru-florida 您是否有机会使用 react-router ?

我使用与您相同的堆栈(打字稿和 create-react-app)以及render属性的问题。 将其更改为component就可以了。

前:

<Route path="/signup" render={SignUp} />

后:

<Route path="/signup" component={SignUp} />

希望能帮助到你..!

@mikeyyyyyy不,在这个中没有使用 React Router。 感谢您的提示,因为我在上一个项目中尝试使用 spring 并且遇到了同样的问题。

我在 npm 链接(在包裹应用程序中)遇到了这个问题, npm link .../whatever/node_modules/react似乎无法解决它,但可以与非钩子组件一起使用

@tj我猜你对 ssr 有问题。 快速解决方法是从链接包中导出反应函数或整个反应并将其导入您的服务器包中

@seeden啊,我没有使用 SSR,只是一个带有包裹的 SPA。 我在内部有一个ui pkg 用于我自己的东西和一个我正在开发的应用程序,两者都有相同的react版本,似乎很奇怪,有重复但也许这是包裹问题

@tj哦,我明白了。 那么祝这个非常奇怪的问题好运。 我用这个花了一个星期

那么这个问题有什么解决办法吗?

这里本身没有问题。 如本页所述,React 需要useState()调用与 $#$ react $#$ 对象在同一react对象上作为从react-dom内部“看到”的对象。 如果这不是发生在你身上的事情,这意味着你在页面上捆绑了两个 React 副本——这本身就很糟糕,并且还破坏了 Hooks 之前的一些其他功能。 所以无论如何你都会想要修复它。 此页面包含诊断修复它的常用方法。

当人们遇到此问题时,我们将开放此讨论以共享特定的解决方法。 但这不是任何人都可以“解决”的问题,除了你。

我在使用 npm 链接(在包裹应用程序中)时遇到了这个问题,npm 链接 .../whatever/node_modules/react 似乎无法解决它,但可以与非挂钩组件一起使用

您介意创建一个小型复制案例吗?

@gaearon会的,下周应该有时间再挖掘一下

令人高兴的是, require-control已经解决了yarn link + SSR + styled-components 4 的静态上下文的问题。 谢谢@theKashey 👍

我在这里尝试了一切,但失败了。 这实际上是不同的东西,这里没有记录。 这与 react 导入的区分大小写有关。 在某些情况下,我们有:

import React from 'react'

在其他方面:

import React from 'React'

在某些文件系统(unix、osx)上,这会导致 Webpack 实例化两个 React 副本。

这引起了极大的混乱,因为我可以清楚地看到我们只有一份 React; 但它是我们导入它的方式。

对反应文档的测试也很好,因为它显然只使用了小写字母。

这听起来可能值得在文档中提及?

对我来说,多个 React 实例的原因是 Webpack DllPlugin。 对于我的供应商 DLL,我没有在我的条目列表中包含reactreact-dom ,但是,我有其他库需要reactreact-dom所以我的 DLL 包含reactreact-dom (快速检查清单 json 文件可以揭示这一点)。 因此,当我运行代码并将 React 导入应用程序时,它是从node_modules加载它的,但在供应商的代码中,他们的 DLL 文件需要 React。

总体:小心 DLL 文件并确保您包含的模块不包含您不需要的额外依赖项,否则您将双重导入它们。

我可以通过将react-hot-loader更新为4.6.0来解决此问题

这为 Parcel 中的npm link东西做了诀窍:

"alias": {
        "react": "../ui/node_modules/react",
        "react-dom": "../ui/node_modules/react-dom"
    }

不确定这是否会尝试用于生产构建,看起来有点hacky,但它至少适用于开发

@theKashey OMG 伙计,它有效! 我尝试了许多人们建议的与此问题相关的不同解决方案:使用package.json deps 进行修改,跨项目跟踪“两个反应”,检查我是否违反了 * 钩子规则(我是不是),但我认为您可以选择

alias: {
      react: path.resolve(path.join(__dirname, './node_modules/react')),
      'react-dom': path.resolve(path.join(__dirname, './node_modules/react-dom'))
    }

允许我们使用app-as-a-lib中的钩子将项目移动到下一个 lvl。

这是生成的webpack.config.js

npm ls react

返回

[email protected] D:\code\project
`-- (empty)

为了我

console.log(window.React1 === window.React2)返回真
在这一点上,我认为这是 SSR 导致的问题

更新。 这确实是由 React-apollo 的 SSR 行为引起的(https://github.com/apollographql/react-apollo/issues/2541)
升级到 2.3.1 修复了它

大家好,我们的团队面临这个问题,并花了几天时间来解决它。

我们的工作解决方案

解决方案A:指定要查找的包裹位置,如上所述

  alias: {
      react: path.resolve(path.join(__dirname, './node_modules/react')),
      'react-dom': path.resolve(path.join(__dirname, './node_modules/react-dom'))
    }

解决方案 B:使用 webpack resolve.modules优先选择正确的 node_modules 文件夹以查找模块

案例背景及其发生的原因

首先,这不是 react 的错,甚至不是 lerna 的错,但是 react、webpack 和 npm-link 可能需要承担一些责任。

案例要求:

-非monorepo:

  • 有符号链接的包
  • 符号链接的包已使用钩子导出组件
  • 创建反应客户端页面

    • 如果在 monorepo 上工作

  • 包符号链接
  • 包有不同版本的依赖项(甚至补丁版本差异),所以即使工作区也会解决安装 2 react
  • 入口包导入了一个使用钩子的符号链接包

例子

结构

- mono repo root
  - packages
    - ComponentWithHooks (peerDependency: react@^16.8.1)
    - ProductA (dependency: ComponentWithHooks, dependency: react@^16.8.4)
    - ProductB (dependency: react@^16.8.1)

一旦使用工作区引导,它将解析为

- mono repo root
  - node_modules
    - react(16.8.1)
  - packages
    - ComponentWithHooks
      - node_modules (empty)
    - ProductA
      - node_modules
        - react(16.8.4)
    - ProductB
      - node_modules (empty)

一旦你使用 webpack 或其他东西提供ProductA ,它将包含 2 个反应实例。

ProductA 中的代码将查找ProductA/node_modules/react

但是导入的 ComponentWithHooks 会寻找mono repo root/node_modules/react

为什么? 还记得 npm 的查找规则吗? 如果它在自己的 node_modules 文件夹中找不到模块,它将寻找父节点的 node_modules...

所以像 webpack 这样的工具默认完美地应用了这个规则。
util mono repo 解决方案变得流行并没有错。
普通包不会注意到这一点,因为它们中的大多数不需要单个实例作为 react 和 redux。

我使用纱线工作区示例进行非常基本的复制时遇到了同样的问题 - https://github.com/mwarger/yarn-workspace-hooks-repro

我有一个component-library ,它是用打字稿写的,并与包裹捆绑在一起。 example-demo将展示这个component-library并且是一个新创建的 CRA 应用程序。 所有常见的包都是用 yarn 吊起来的,所以理论上应该只有一个可用的 react 版本。 但是,我在 index.tsx 中进行的React.useEffect调用会导致导致我遇到此 GitHub 问题的错误。

在添加钩子之前一切正常。 要重现该错误,请取消注释component-library/src/index.tsx中的第 7-9 行

希望我正在做一些我忽略的愚蠢的事情。 请告知我可以用来尝试解决此问题的任何步骤。 谢谢!

后续编辑:下面建议的调试脚本输出为我打印true 。 看来我没有两个 React。

// Add this in node_modules/react-dom/index.js
window.React1 = require('react');

// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);

花了我几个小时,所以可能值得在这里记下。

在我的例子中,我在 HTML 模板的头部放置了一行<script defer src="./dist/bundle.js" /> ,这在不使用 React 钩子时正常工作。 所有解决方案都不起作用,在这种情况下window.React1 == window.React2检查返回true

由于 webpack 之后会注入 script 标签,所以模板本身不应该有 script 标签。 从模板中删除脚本标签,使 React 再次使用钩子(双关语)起作用。

在我的情况下,我有一个 React 应用程序,它是 npm 链接到我正在处理的依赖项。 这将起到作用,直到我可以修复几个需要将reactreact-dom移动到开发和对等部门的依赖项。

  1. 从应用程序: cd node_modules/react && npm link
  2. 从应用程序: cd node_modules/react-dom && npm link react
  3. 从链接的包中: npm link react

为什么它有效? 错误警告页面提到“为了让 Hooks 工作,应用程序代码中的 react 导入需要解析为与 react-dom 包内部的 react 导入相同的模块”。

尽管尝试了上述所有方法,但我仍然遇到此问题。 标准 webpack4/babel 配置,带有preset-envpreset-react插件。 我的 react/react-dom 版本使用纱线分辨率固定到16.8.4 (上面的window.React1 === window.React2检查也返回true )。

这是最基本的用法:

import React, { useState } from "react";

function MyComp() {
  const [hello] = useState(0);

  return <div>HELLO {hello}</div>;
}
export default MyComp;

有没有人有任何其他想法?

编辑:为了澄清,错误显示为react.development.js:88 Uncaught Invariant Violation: Hooks can only be called inside the body of a function component.根据 OP

在我的情况下,我有一个 React 应用程序,它是 npm 链接到我正在处理的依赖项。 这将起到作用,直到我可以修复几个需要将reactreact-dom移动到开发和对等部门的依赖项。

  1. 从应用程序: cd node_modules/react && npm link
  2. 从应用程序: cd node_modules/react-dom && npm link react
  3. 从链接的包中: npm link react

为什么它有效? 错误警告页面提到“为了让 Hooks 工作,应用程序代码中的 react 导入需要解析为与 react-dom 包内部的 react 导入相同的模块”。

谢谢! 这对我很有用。 (即使我使用 npm 链接和符号链接混合的情况)

我已经尝试了上面所有的建议,但仍然有错误。

@inverherive的帮助下,我们发现enzyme-adapter-react-16仍然会导致问题。

虽然我们将react-test-renderer更新到最新版本 (16.8.4),因为它最近才添加了 hooks 支持,但我们通过npm ls react-test-renderer发现最新版本的enzyme-adapter-react-16 (1.11.2 ) 具有[email protected]的内部依赖关系,它不支持挂钩。

├─┬ [email protected]
│ └── [email protected] 
└── [email protected]

为了解决这个问题,以及遵循@chulanovskyi修复,当我们使用纱线时,我们在 package.json 中添加了react-test-renderer分辨率。 这会强制react-test-renderer的所有引用使用“16.8.4”。

  "resolutions": {
    "react-test-renderer": "16.8.4"
  },

这非常令人沮丧,希望这可以帮助其他人。 感谢@chulanovskyi@theKashey的建议。

这将起到作用,直到我可以修复一些需要将 react 和 react-dom 移动到 dev 和 peer deps 的依赖项。

@ajcrews (我可能错过了一些东西,但是)我npm link中有一个内部库,并且该库在peerDependenciesdevDependencies react我仍然需要你的修复不管以解决错误。 很好的发现!

我正要发帖,但找到了解决方案

我有一个组件库,里面有一个用于开发的示例 CRA 应用程序

在 CRA 应用程序的 package.json 中,我必须修改 react 和 react-dom 以从根组件的 package.json 中“借用”

"dependencies": {
  "react": "link:../node_modules/react",
  "react-dom": "link:../node_modules/reac-dom",
}

这非常令人沮丧,希望这可以帮助其他人。 感谢@chulanovskyi@theKashey的建议。

@Paddy-Hamilton 安装后始终检查您的锁定文件。 我遇到了yarn复制react-test-renderer的相同问题。 在您的锁定文件中进行一些手术,您可以解决这些问题:

yarn add -D react-test-renderer

-react-test-renderer@^16.0.0-0, react-test-renderer@^16.1.1:
+react-test-renderer@^16.0.0-0:
  version "16.8.4"
  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.4.tgz#abee4c2c3bf967a8892a7b37f77370c5570d5329"
  integrity sha512-jQ9Tf/ilIGSr55Cz23AZ/7H3ABEdo9oy2zF9nDHZyhLHDSLKuoILxw2ifpBfuuwQvj4LCoqdru9iZf7gwFH28A==
  dependencies:
    object-assign "^4.1.1"
    prop-types "^15.6.2"
    react-is "^16.8.4"
    scheduler "^0.13.4"

+react-test-renderer@^16.8.5:
+  version "16.8.5"
+  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.5.tgz#4cba7a8aad73f7e8a0bc4379a0fe21632886a563"
+  integrity sha512-/pFpHYQH4f35OqOae/DgOCXJDxBqD3K3akVfDhLgR0qYHoHjnICI/XS9QDwIhbrOFHWL7okVW9kKMaHuKvt2ng==
+  dependencies:
+    object-assign "^4.1.1"
+    prop-types "^15.6.2"
+    react-is "^16.8.5"
+    scheduler "^0.13.5"

yarn check已经警告你了

$ yarn check
warning "enzyme-adapter-react-16#react-test-renderer@^16.0.0-0" could be deduped from "16.8.5" to "[email protected]"

然后通过应用以下补丁手动对其进行重复数据删除:

-react-test-renderer@^16.0.0-0:
-  version "16.8.4"
-  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.4.tgz#abee4c2c3bf967a8892a7b37f77370c5570d5329"
-  integrity sha512-jQ9Tf/ilIGSr55Cz23AZ/7H3ABEdo9oy2zF9nDHZyhLHDSLKuoILxw2ifpBfuuwQvj4LCoqdru9iZf7gwFH28A==
-  dependencies:
-    object-assign "^4.1.1"
-    prop-types "^15.6.2"
-    react-is "^16.8.4"
-    scheduler "^0.13.4"
-
-react-test-renderer@^16.8.5:
+react-test-renderer@^16.0.0-0, react-test-renderer@^16.8.5:

现在您有了一个没有任何resolutionswebpack别名恶作剧的react-test-renderer版本。

对于与链接包和create-react-app相关的任何问题,请关注 facebook/create-react-app#6207

有很多方法可以解决它,而纱线分辨率通常无济于事——它与“构建工具”更相关

  • 对于 webpack 使用aliases - 只是“硬”别名,一切都像react到单个文件中
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: {
     react: path.resolve(path.join(__dirname, './node_modules/react')),
   }
import {setAliases} from 'require-control';
setAliases({
  'react': path.resolve(path.join(__dirname, './node_modules/react'))
});
  • 开玩笑用moduleNameMapper
"jest": {
    "moduleNameMapper": {
      "^react$": "<rootDir>/node_modules/$1",
    },

这为我做到了。

@ajcrews
谢谢! 对我来说效果很好!

我使用 react 16.8.6、electron-webpack 和 RHL 做了一个最小设置的小测试用例。 值得注意的是,当这个错误发生时,整个浏览器(在这个设置中,电子)刚刚开始消耗大量的 CPU 时间)

https://github.com/PerfectCSGO/reeee

我已经为这个问题头疼了三天了。 最初我认为 RHL 是问题所在,但将其完全从该项目中删除并不能解决问题。

npm ls react 只返回一个结果。 我确保上述修复适用于最新版本 + webpack 别名。

该代码将在沙箱中运行。

在一个简单的 webpack/website 中,代码将毫无问题地工作。 但是,使用 electron-webpack,这个问题仍然存在。

  "dependencies": {
    "i18next": "^15.0.9",
    "i18next-browser-languagedetector": "^3.0.1",
    "react": "^16.8.6",
    "react-dom": "npm:@hot-loader/react-dom",
    "react-hot-loader": "^4.8.2",
    "react-i18next": "^10.6.1",
    "source-map-support": "^0.5.11",
    "tslint": "^5.15.0"
  },
  "devDependencies": {
    "@babel/core": "^7.4.3",
    "@babel/preset-react": "^7.0.0",
    "@babel/preset-typescript": "^7.3.3",
    "@types/react": "^16.8.12",
    "@types/react-dom": "^16.8.3",
    "electron": "^4.1.3",
    "electron-builder": "20.39.0",
    "electron-webpack": "^2.6.2",
    "electron-webpack-ts": "^3.1.1",
    "typescript": "^3.4.1",
    "webpack": "^4.29.6"
  }

希望有人能给我指点...

当我用 mobx-react-lite 替换 react-l18next 并使用观察者时,它会产生相同的效果。

关于我的问题,我通过使用电子 webpack 解决了这个问题,并采用了更“纯”的电子解决方案。 我的猜测是它是在 webpack 或 babel 中使用的不兼容的工具链。

我只在生产中遇到过这个问题。 这里提出的解决方案都没有帮助。
我的用例是第三方应用程序,它作为小部件加载到另一个网站。
当网站第一次加载小部件时一切正常,但是当用户导航到不同的页面并返回到带有小部件的页面时,我得到了钩子错误。

请注意,该错误仅在导航不会导致页面重新加载时发生。

我花了几个小时试图找出问题所在。 最后,问题在于加载应用程序包的代码片段。 在页面更改时,捆绑包可能会加载多次,这导致我猜测同一名称空间中有多个 React 实例。

我通过检查脚本是否已经加载来修复它。
首先,我使用 Webpack 的“库”配置将库导出到全局命名空间:

output: {
    library: 'myLib',
    ...
}

然后在加载脚本中我检查了库是否存在:

if(!window.myLib){
    var bz = document.createElement('script');
    bz.type = 'text/javascript'; 
    bz.async = true;
    bz.src = 'https://path/to/bundle.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(bz, s);
}

这可能是一个非常具体的用例,但我希望这可以帮助其他人。

所以我们有一个利用 webpack 的主要 React 应用程序。
我们正在尝试创建一个使用 hooks 的小型 React 库,我们尝试更换捆绑器(parcel、pure babel、webpack)。
在尝试我们的 webpack 实现时,我们将 react 和 react-dom 标记为外部,因此我们不会将它们包含在我们的包中。
使用 npm 链接时,我们仍然会遇到相同的钩子异常。

创建到主应用程序的反应的符号链接确实有效,但这不是一个很好的开发工作流程。

我很难找出问题的根本原因。 是什么产生了重复的 React 实例?

嗨@adriene-orange,您可能会找到我的帖子https://github.com/facebook/react/issues/13991#issuecomment -472740798 以获得更多解释。

npm 链接导致的多实例是因为如果在您的包中找不到该模块,默认情况下节点会在父文件夹的 node_modules 中查找该模块。

我们为此找到的最简单和最好的解决方案是在你的入口包的 webpack(或其他工具)配置中,有类似resolve.modules的东西来手动设置路径和 webpack 将查找模块的路径的顺序。 exp., resolve: { modules: [path.resolve(PACKAGE_ROOT, 'node_modules'), 'node_modules'] }会强制 webpack 先在你的入口包根的 node_module 中查找模块。 如果在根目录下找不到模块,则在相对的 node_modules 文件夹中查找...

所以我们有一个利用 webpack 的主要 React 应用程序。
我们正在尝试创建一个使用 hooks 的小型 React 库,我们尝试更换捆绑器(parcel、pure babel、webpack)。
在尝试我们的 webpack 实现时,我们将 react 和 react-dom 标记为外部,因此我们不会将它们包含在我们的包中。
使用 npm 链接时,我们仍然会遇到相同的钩子异常。

创建到主应用程序的反应的符号链接确实有效,但这不是一个很好的开发工作流程。

我很难找出问题的根本原因。 是什么产生了重复的 React 实例?

嗨我收到这个错误

不变违规:无效的挂钩调用。 Hooks 只能在函数组件的主体内部调用。 这可能由于以下原因之一而发生:
1. React 和渲染器的版本可能不匹配(例如 React DOM)
2. 你可能违反了 Hooks 规则
3. 你可能在同一个应用程序中拥有多个 React 副本
有关如何调试和修复此问题的提示,请参阅https://fb.me/react-invalid-hook-call

   5 | 
   6 | const useApiHelper = (url, reducer) => {
>  7 |     const [state, dispatch] = useReducer(reducer, {});
     |                                                  ^
   8 | 
   9 |     useEffect(() => {
  10 |         fetch(url).then(res => res.json())

示例代码https://stackblitz.com/edit/react-mbze9q

当我尝试在测试用例中访问此功能时,我遇到了错误

@abhishekguru您在测试中在组件之外调用 Hook:

test('API test', async () => {
  const newState = useAPIHelper( // <- Called outside of a component
    'https://jsonplaceholder.typicode.com/posts',
    reducer
  )
  console.log(newState, 'new');
  // expect(newState[samUrl].loading).toEqual(true);
});

由于错误状态,只能从另一个钩子或组件内调用钩子。 在您的情况下,您可以为您的测试创建一个组件,并根据需要渲染使用钩子的组件。

无耻的插头

@abhishekguru如果您在多个组件之间使用了一个通用挂钩,并且您想独立于任何特定组件对其进行测试,您可以考虑使用react-hooks-testing-library

import { renderHook } from 'react-hooks-testing-library'

test('API test', async () => {
  const { result } = renderHook(() => useAPIHelper( // <- now called within a component
    'https://jsonplaceholder.typicode.com/posts',
    reducer
  ))

  console.log(result.current, 'new');
  // expect(result.current[samUrl].loading).toEqual(true);
});

我想在这里插话,因为我们只有 SSR 的问题。 我们在文件更改时清除节点的require.cache 。 这有效地在服务器上提供了热重载。 清除节点的require.cache将导致需要单个副本的库出现问题。 这是我们的解决方案:

Object.keys(require.cache)
  .filter(key => !isSingleton(key)) // This is needed here because react cannot be deleted without causing errors
  .forEach(key => {
    delete require.cache[key]
  })

我们的isSingleton函数包含必须具有单个副本的库列表。 一个好的经验法则是任何需要在peerDependencies中定义的库

https://yarnpkg.com/lang/en/docs/dependency-types/#toc -peerdependencies

也有同样的问题,对我来说

window.React1 = require('react');
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2); // true

还返回true ,尝试了所有给定的建议,但没有任何效果。 最后结果是:

Webpack 会自动将带有bundle.js的脚本标签添加到index.html中。 我的问题是因为我bundle.js添加到index.html中,这在挂钩之前可以正常工作。

对我来说,问题是在 babel 7 升级之后,没有单独的 npm ls react 版本。 移除
.babelrc 中的“react-hot-loader/babel”暂时修复了这个问题。

我尝试了上述所有解决方案,但仍然出现错误。
最终,我发现它是由包why-did-you-update引起的,并且有一个相关的问题。 任何人使用修改 React 的类似包只是一个线索。

我能够在react-native + Yarn Workspaces场景中解决这个问题。


在根package.json

{
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "**/react-native",
      "**/react-native/!(react)/**"
    ]
  }
}

这可以防止react-native代码被提升(这是本机反应所需要的),同时仍然提升react ,因此所有共享模块都使用相同的反应。


metro.config.js

module.exports = {
  watchFolders: [
    path.resolve(__dirname, '../', 'shared-module'), 
    // ...more modules
    path.resolve(__dirname, '../', '../') // to make sure the root `react` is also part of the haste module map
  ]
}

Metro 配置让捆绑器知道所有东西在哪里。

例如,我为在本地开发 npm 包的人找到了一种解决问题的方法,他们试图通过在某种示例应用程序中使用 npm 链接加载他们的包来在本地测试它。

我从示例应用程序(测试组件的原始方式)切换到Storybook 。 在项目中使用故事书时,它不会加载 React 两次,因为它将使用组件正在使用的同一个。 在使用 npm link 时,我遇到了 hooks 和 React 被加载两次的问题,我也无法让上述任何解决方案发挥作用。 所以 Storybook 解决了我的问题,现在我有办法通过多个场景测试我的组件,同时为它构建一些交互式文档。

分享我的经验,为我们的项目解决了这个问题,方法是使用组件库的webpack 外部组件从构建中排除reactreact-dom

我们只是从 React 开始。 就我而言,我们从带有 Neutrino 组件库包和 Neutrino webapp 客户端包的 Lerna monorepo 开始。 webapp 使用链接组件库的构建产品。 经过一些试验并为同一个 React 实例获得了true ,我已经寻找一种方法来从组件库的构建中完全排除reactreact-dom

这似乎是 webpack 组件库的常见设计模式解决方案,因此在组件库中我已添加到 webpack 配置中:

"externals": {
  "react": "react",
  "react-dom": "react-dom"
}

我不需要在reactreact-dom的 webapp 包中放置全局脚本标记。 我猜 Webpack 在它的require实现中向组件库提供这些组件库,就像它向 webapp 提供的一样。

此错误的另一个原因是错误配置 React Router 的Route

失败了

<Route render={MyHookedComponent}/>

,但这成功了:

<Route component={MyHookedComponent}/>

例如。 您需要使用component而不是render 。 这是一个容易犯的错误,因为render通常适用于基于类的组件。

我正在研究 biolerplate 并希望将其发布到 npm,并在npm link的帮助下开发它工作正常,但一段时间后开始出现错误Invalid Hook call warning
我尝试使用 npm link ../myapp/node_modules/react 但它并没有解决我的问题,
React1 === React2相比,它是 true 以及npm ls react也是如此,它只显示一个包。

而且我也没有使用 webpack,我只是在 create-react-app 之外添加了一些层,所以我不能强迫我的应用程序使用本地安装的 react 模块。
从过去 3 天开始就一直坚持下去。_

@hnagarkoti相同。

我在服务器端渲染 (SSR) 期间遇到了这个警告,因为我使用的是旧版本的react-apollo ,所以只是想把这个链接留在这里,以帮助遇到这个问题的下一个可怜的灵魂:

https://github.com/apollographql/react-apollo/issues/2541

简而言之, getDataFromTree直到版本[email protected]才支持反应钩子。

我有同样的问题,我通过添加解决了它:

 alias: {
        react: path.resolve('./node_modules/react')
      }

到我的主应用程序的 webpack 配置中的resolve属性。

使用两个 React 副本显然是我的错误,但我同意如果错误消息更好,那就太好了。 我认为这可能类似于:#2402

对使用 create-react-app 执行此操作有什么建议吗?

^ 好的,我为 create-react-app 解决这个问题的解决方案是使用react-app-rewiredcustomize-cra。

这是我的 config-overrides.js :

const {
    override,
    addWebpackAlias,
  } = require("customize-cra");

const path = require('path'); 

module.exports = override( 
    addWebpackAlias({
        react: path.resolve('./node_modules/react')
    })
)

示例项目: https ://github.com/dwjohnston/material-ui-hooks-issue/tree/master

在我们的团队中,我们有一个通用的导航组件可以跨数十个应用程序工作,所有这些应用程序都来自 react 15.0.0 到 react 16.8.0,为了启用在 hooks 上实现的导航,我们必须将它与最新的 react 捆绑在一起

在这种情况下,react 的多个实例对我们来说是一个基本要求,我想知道 react 官方团队以后是否愿意解决这个问题?

@dwjohnstoncreate-react-app的解决方法是为开发创建一个 webpack 配置。 create-react-app内部使用 webpack、webpack-dev-server 和 babel-loader,因此创建一个 webpack 配置只是为了开发并不算太糟糕,因为依赖关系已经隐含在那里,但仍然需要大量开销正常工作。

我在create-react-app上有一个问题: https ://github.com/facebook/create-react-app/issues/6953 添加webpack alias支持或类似的。

👋如果有人也在使用create-react-app并遇到这个痛点,请您给这个问题点个赞吗?

@ricokahler - 感谢您指出这一点。 我很高兴看到我不是唯一一个遇到这个问题的人——我也遇到过这个问题。

你知道有没有进一步讨论这个问题的资源?

如果你在我的船上,你已经从本地目录添加了一个 react 组件包,现在它会自动构建和安装它,以及它自己的 node_modules 副本(因为它使用 npm 链接来执行此操作),给你应用程序 2 副本或立即反应。

我已经通过删除 node_modules/ 来解决它/node_modules 在运行应用程序之前。 要自动执行此操作:

"prestart": "rimraf ./node_modules/<my_package>/node_modules"

我在做 SSR 时也遇到过这个问题。
如果你使用Lerna在本地测试你的 React 库,你可以在你的库中添加“react/react-dom/react-router”作为 peerDependencies,但你不应该将它们添加为 devDependencies。 (这使它重复)
您可以使用node --preserve-symlinks以便它可以查找安装 peerDependencies 的父 repo。
对于 jest,您需要将父 repo 路径添加到“jest.moduleDirectories”选项,以便 Jest 可以解决它们

@apieceofbart它对我有用,谢谢!

我在加载外部 React 组件时遇到了这个错误,例如使用 JS 模块。 它们完全在项目之外,加载了动态 import() (以及 jsonp 以获得更多支持)。 为了解决这个问题,我们将 React 作为属性传递/注入到每个模块。 这可行,但是每个模块都依赖于包含的 React 应用程序。 我们正在尝试删除依赖项。

正如其他人所提到的,此属性消除了 React 可用于任何类型的微前端。 问题是在导入 React 以用作库时,在 JS 运行时中创建全局状态会产生这种副作用。

我知道对于简单的用例,具有这种副作用意味着 React “更易于使用”。 但是当一个网页由来自多个捆绑步骤的多个脚本组成时,其中一个应该能够设置 React(显式地执行该副作用),而其他的可以简单地调用库函数。

我仍然对 react-bootstrap 有疑问:# https://github.com/react-bootstrap/react-bootstrap/issues/3965

对于其他坚持尝试为 React 制作库的人,请尝试https://github.com/whitecolor/yalc ,它比符号链接好得多。

@mpeyper效果很好。 谢谢

@apieceofbart这对我有用。 谢谢你的建议。 👍

对我来说,当我在 PowerShell 中导航到我的项目目录并且没有将路径中的目录名称大写时导致了这个问题。 我在 users/.../... 而不是 Users/.../... 中创建了项目
当我修复大写错误并重新创建项目时,该问题得到解决。

对我来说,做:

    "react": "file:../my-library/node_modules/react",
    "react-dom": "file:../my-library/node_modules/react-dom",

修复了大部分但还不够,我不断收到错误hooks can only be called inside the body of a function component

原来是因为我的库的一些组件是这样导出的:

export default Radium(withTranslation()(MyComponent))

:X:

其中withTranslation是 react-i18next 的 HOC, Radium是 Radium 的 HOC。

并像这样导出它们:

export default withTranslation()(Radium(MyComponent))

:heavy_check_mark:
修复了一切。

请注意,react-i18next 是使用 React Hooks 的版本 10

@mikeaustin我们遇到了同样的问题。 您是否有任何“将 React 作为属性传递/注入每个模块”的示例?

仍然遇到此问题,尝试了所有步骤:

  • 纱线工作区(通过 lerna)
  • 检查是否有一个反应部门,是的

一些可能会产生影响的事情:

  • 将 webpack 与 libraryTarget 一起使用
  • 使用打字稿
$ npm ls react-dom
/xxx
└── [email protected]

$ npm ls react
/xxx
└── [email protected]

根包.json

{
  ...
  "workspaces": [
    "packages/*",
  ],
  "devDependencies": {
    ...
  },
  "dependencies": {
    "react": "16.8.6",
    "react-dom": "16.8.6"
  },
  "resolutions": {
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "**/react": "16.8.6",
    "**/react-dom": "16.8.6"
  }
}

@JeremyGrieshop我遇到了同样的问题,这对我有用,谢谢。

在您的 package.json 中添加“prestart”,如下所示:

"scripts": {
    "prestart": "rimraf ./node_modules/<my package>/node_modules",
    "start": "react-scripts start",
    "build": "react-scripts build",
  },

我遇到了这个问题,这不是由于多个版本的 react / react-dom
在我使用的自定义工具中,需要缓存被清除(出于本讨论之外的目的),例如:

Object.keys(require.cache).forEach((key) => {
      delete require.cache[key];
    });

所以仅供参考,如果你正在做这样的事情 - 它会影响 React Hooks,所以如果你可以避免它

我有同样的问题,我通过添加解决了它:

 alias: {
        react: path.resolve('./node_modules/react')
      }

到我的主应用程序的 webpack 配置中的resolve属性。

使用两个 React 副本显然是我的错误,但我同意如果错误消息更好,那就太好了。 我认为这可能类似于:#2402

对于使用 Parcel 的任何人,如果dist是您的编译文件所在的位置,您应该添加:

  "alias": {
    "react-mediator": "./dist"
  },

到你的package.json然后你仍然可以link (npm 或 yarn) 库进行本地开发/测试。

@mikeaustin我们遇到了同样的问题。 您是否有任何“将 React 作为属性传递/注入每个模块”的示例?

您可以使用 React Context 传递“React”本身,并创建一个 HoC 将属性注入每个组件。 你可以在 api 中传递任何东西,比如 api.React,但是在这些组件周围包装 HoC 会有点棘手(因为现在它们只能在组件内部使用,不能导出。

const withReact = Component = props => (
  <ReactContext.Provider value={api => <Component api={api} {...props} /> } />
)

我花了几个小时,如果更改源代码以更改错误消息并向其添加更多信息并不容易并且您需要更多时间,至少将此注释添加到文档中,

_p.s:react 有很好的文档,但我认为该页面需要审查。_

@奥利弗拉迪尼

我可以通过将react-hot-loader更新为^4.6.0来解决此问题

Maaan,解决了它。
@gaearon @theKashey将其添加到https://reactjs.org/warnings/invalid-hook-call-warning.html怎么样,这样人们就不会因为react-hot-loader的旧版本而浪费时间?

我认为它已经很好地记录了十几个问题。

嗨,我在应用程序中都使用 React。 我使用应用程序内的库。 我设法通过使用解决了两个反应实例问题:

应用程序webpack 配置中:

    alias: { react: path.resolve( '__dirname', '..',  'node_modules', 'react' ) // Adapt this to match your file tree

webpack 配置中

  externals: {
    react: 'react', // Case matters here
    'react-dom': 'react-dom' // Case matters here
  }

所以我遇到了从非转译文件(* .js)调用钩子的问题:

index.js :

import ReactDOM from 'react-dom';
import './index.css';
import App from './app';

ReactDOM.render(App(), document.getElementById('root'));

app.jsx

import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
const BaseContext = React.createContext();

const initialState = {
  woo: true
};

const reducer = (state, action) => {
  switch (action.type) {
    default:
      return state;
  }
};

const Home = () => <h1>You're at home.</h1>;

const App = () => {
  // eslint-disable-next-line
  const [state, dispatch] = React.useReducer(reducer, initialState);
  return (
    <Router>
      <BaseContext.Provider value={initialState}>
        <BaseContext.Consumer>
          <div className="welcome">
            <nav>
              <ul>
                <li>
                  <Link to="/">Home</Link>
                </li>
              </ul>
            </nav>
            <header className="header">
              <h1>Welcome!</h1>
            </header>
            <Route path="/" exact component={Home} />
          </div>
        </BaseContext.Consumer>
      </BaseContext.Provider>
    </Router>
  );
};
export default App;

任何建议,假设它不是“将其移至 JSX 文件并转译”?

似乎没有什么对我有用,我混合使用了刺激和反应,我有一个混合应用程序,开始使用钩子,但我一开始添加 turbolinks 就失败了:(

编辑:现在我通过将data-turbolinks-track="reload" data-turbolinks-eval="false"添加到我正在使用的脚本标签来解决我的问题,所以现在应该这样做

我也有同样的问题,4 小时后,我发现 jenkins util 缺少将 .babelrc 文件转换为服务器。

为什么这会产生错误?

$ npm ls react
[email protected] /mnt/g/development/javascript/pow-vehmain
└── [email protected]`
Invalid hook call...
ServiceVisitMaintenance
src/components/ServiceVisit/ServiceVisitMaintenance.js:6
  3 | import { ServiceVisitForm } from './ServiceVisitForm';
  4 | 
  5 | const data = [{ id: 1, description: 'Ford' }, { id: 10, description: 'Edsel' }];
> 6 | const ServiceVisitMaintenance = () => {
  7 |   const [vehicleList, setVehicleList] = useState([]);
  8 |   return (
  9 |     <div>

ServiceVisitMaintenance.js:

import React, { useState } from 'react';
import { ServiceVisitForm } from './ServiceVisitForm';
const data = [{ id: 1, description: 'Ford' }, { id: 10, description: 'Edsel' }];
const ServiceVisitMaintenance = () => {
  const [vehicleList, setVehicleList] = useState([]);
  return (
    <div>
      <ServiceVisitForm vehicleList={data} />
    </div>
  );
};

export { ServiceVisitMaintenance };

请检查您的 react-dom 版本是什么。

$ npm ls 反应域
[email protected] /mnt/g/development/javascript/pow-vehmain
└── [email protected]

当我从库中导出一个 connect(mapStateToProps)(MyComponent) 并在我的 CRA 应用程序中使用该库时,我遇到了这个问题。

不,这是我的严重错误。 调用它的例程使用 react-router-dom 并使用渲染道具而不是组件。

你们有没有人有同样的问题,但盖茨比?

我在“npm ls react”后得到以下结果:
image

和'npm ls react-dom'
image

一开始还以为是我不小心全局安装了react,全局卸载后什么都没变。 然后,我尝试在不同的目录中创建一个全新的项目,“gatsby new random-name”并添加了一个小功能(添加评论,跟随 https://www.youtube.com/watch?v=asrdFuAxPaU&feature=youtu .be) 到 gatsby-starter-default 以测试错误是否会自行重现。 好吧,令我懊恼的是,它做到了!

任何和所有的建议都会受到沮丧的民众的欢迎。

我仍然在故事书中面临这个问题。 npm ls 的输出是否正确?
imageimage

就我而言,问题是由why-did-you-update模块引起的。

使用工作空间和 lerna monorepo 并提升包。 这将解决问题。

我们对 SSR 也有同样的问题。 它似乎可以通过在我们的 webpack 配置中设置externals: [“react”]然后手动加载react/umd/react.development.js来工作。 但是,这很痛苦,并且很想找到一种更简单的方法。

好的,希望这对某人有所帮助。 我们不小心多次加载了 webpack runtime.js,导致存在多个 React 副本。 确保只加载一次 runtimeChunk (runtime.js)。

如果您像我一样在 Jest 测试中遇到问题,这似乎可以为我解决问题。
将此添加到您的jest.config.js

moduleNameMapper: {
    '^react$': '<rootDir>/node_modules/react/'
  }

如果这个错误至少指向它发生的文件,那就太好了。 我不小心在正常函数中调用了一个钩子,并且很难调试。

我找到了问题的另一个原因和解决方案。

我的环境是electronwebpack但这也可能对非电子人员有所帮助。 在升级到 React 16.9(和 React DOM 16.9)后,我花了很多时间试图解决为什么会收到此错误消息。

在我的情况下,我似乎在应用程序中有两个 React,但我在 node_modules 中找不到两个物理库,甚至没有使用npm ls react 。 我什至用webpack-bundle-analyzer来看看包里面有什么。

最终,我发现我在项目中没有两个物理反应,但是React 和 React DOM 在 HTML 文件中被引用/加载了两次。 这可以通过在 React 库的 index.js 中添加例如console.log("React load")来轻松检查。

真正的来源连接到electron-webpackreact 和 react-dom 没有被标记为外部,因此被加载到包中以及后来从 node_modules 加载,因为在其他模块中使用了 require 。

解决方案就像将这些行添加到webpack.renderer.config.js一样简单:

module.exports = {
    externals: [
        "react",
        "react-dom"
    ],
};

好的,所以如果这里有人使用 parcel.js,出于某种奇怪的原因,我能够摆脱以下导入: import React from 'React';并且一旦我开始使用反应钩子,我就得到了不变违规错误,没有意识到它是因为我不正确地使用from 'React'而不是from 'react'导入。 哎呀。

你们有没有人有同样的问题,但盖茨比?

我在“npm ls react”后得到以下结果:
image

和'npm ls react-dom'
image

一开始还以为是我不小心全局安装了react,全局卸载后什么都没变。 然后,我尝试在不同的目录中创建一个全新的项目,“gatsby new random-name”并添加了一个小功能(添加评论,跟随 https://www.youtube.com/watch?v=asrdFuAxPaU&feature=youtu .be) 到 gatsby-starter-default 以测试错误是否会自行重现。 好吧,令我懊恼的是,它做到了!

任何和所有的建议都会受到沮丧的民众的欢迎。

是的,我遇到了和你一样的问题。 我已经听从了这里的建议......

// Add this in node_modules/react-dom/index.js
window.React1 = require('react');

// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);

我将 React2 添加到页面下的索引文件中。 它返回假。

去重意味着 npm 应该对依赖项进行去重,请参见此处...

同一个包不必安装两次! 它只是参考。

此外,它将包“向上”移动(使树变平)。 这是完全有意义的,否则一个包将不得不查看其他包的 node_modules (这会有点混乱)并有助于简化依赖关系。

您可以验证这一点,因为在您的依赖图中,每个包都显示重复数据删除,可以在图中至少再找到一次,通常在“更高级别”。

尽管显然重复数据删除没有奏效。

你试过什么?

尝试使用 NextJS 构建时出现此错误。 有些组件使用material-ui,如果我删除它们,问题就会消失。 我不使用样式组件。 我尝试删除 node_modules 等,但没有运气。 我尝试在我的 next.config.js 文件和 package.json 中添加别名并解析react ,但没有成功。 我正在使用 react 16.8.6、react-dom 16.8.6 和下一个 9.0.4。 npm ls表示每个只有一个。 我没有使用任何 npm 链接。

存储库: https ://github.com/dancancro/questions/tree/invalid-hook-call

Codesandbox 在这里: https ://codesandbox.io/s/github/dancancro/questions/tree/invalid-hook-call/?fontsize=14

Stackoverflow: https ://stackoverflow.com/questions/57647040/nextjs-invalid-hook-call-hooks-can-only-be-call-inside-of-the-body-of-a-fun

错误在这里:https://gist.github.com/dancancro/2dfafb053aaaedfade406fd4f67eb68a
...渲染 -> renderToString -> ReactDOMServerRenderer.read -> ReactDOMServerRenderer.render -> Object.WithStyles [作为渲染] ...

有问题的钩子是withStyles函数中以下文件的第 17428 行上的useStyles()调用。 搜索“var classes = useStyles(props)”。 问题在于 nextjs 生成的代码。 我写的代码没有使用withStyles或任何以“use*”开头的钩子或任何函数

https://raw.githubusercontent.com/dancancro/questions/invalid-hook-call/.next/static/development/pages/index.js

更新:从我的 next.config.js 中删除它解决了这个问题:

    webpack: config => {
        config.externals = [
            '/'
        ]
        return config
    },

我通过从链接包的node_modules文件夹中删除reactreact-dom发现了一种解决方法。

我和你们很多人在同一条船上。 我有一个正在本地处理的库包,我不想在每次需要查看应用程序包的更改时都麻烦地发布它。 我链接它并开始收到此错误。

这是解决方法:

  • 包 A:你的库代码包,已经npm link 'd
  • 包 B:您的应用程序代码包。 包 A 的node_modules文件夹中有一个符号链接
  1. 构建包 A. Mine 将其资产输出到dist/ ,包括它的node_modules
  2. 在包A分发的node_modules文件夹中,删除reactreact-dom
  3. ???
  4. 利润!

请注意,我在两个包中都安装了相同版本的 React。 您必须重新启动所有正在运行的进程。

删除不兼容的why-did-you-update对我有用。 (https://github.com/maicki/why-did-you-update/issues/52)

不兼容你为什么更新

@bertho-zero 使用可以使用新的 devtools 或我的钩子useWhyDidYouUpdate

@brunolemos这很棒,但更受限制,因为您必须将它放在每个组件上。

@dmart914的解决方案为我解决了这个问题。 我也链接了包,这样我就可以在不发布更改的情况下测试我的库...有没有人找到解决方法? 发布一个开源库并且必须记录删除特定 NPM 包以使钩子神奇地开始工作,这不是一个很好的体验……

如果该包具有需要react的测试(例如@testing-library/react@testing-library/react-hooks ),则删除链接包的react模块的解决方案不起作用,所以它看起来我们仍然需要更好的方法来处理这个问题。

我的申请由两部分组成。 主 Web 应用程序和一个动态加载到 Web 应用程序中的模块。 Web 应用程序和模块都使用 React 16.9.0。
使用 React.lazy() 和动态 import() 语句将该模块加载到 Web 应用程序中。
加载模块时,会引发“无效的挂钩调用”错误。

就我而言,由于主应用程序和模块是分开构建的,因此它们彼此不了解,并且将拥有自己的 react 副本。 我尝试了在线程中找到的以下建议,但没有解决问题。

  1. 在模块的 webpack.config 中添加一个别名,该别名指向 apieceofbart 建议的主应用程序的反应。
    别名:{
    反应:path.resolve('../../node_modules/react')
    }

  2. 试图将模块的 package.json 中的 react 依赖项指向主应用程序。
    “依赖”:{
    “react-dom”:“文件:../common/node_modules/react-dom ”,
    “反应”:“文件:../common/node_modules/react
    }

我认为当涉及到动态加载的模块时,react 必须支持运行多个副本。

根据上面的一些回复,这对我有用:

  1. 将以下内容添加到config/webpack.config.js
externals: {
  react: {
    root: 'React',
    commonjs2: 'react',
    commonjs: 'react',
    amd: 'react'
  },
  'react-dom': {
    root: 'ReactDOM',
    commonjs2: 'react-dom',
    commonjs: 'react-dom',
    amd: 'react-dom'
  }
}
  1. 已编辑package.json
"devDependencies" : {
  ...
  "react": "^16.9.0",
  "react-dom": "^16.9.0",
}
"peerDependencies": {
  "react": "^16.9.0",
  "react-dom": "^16.9.0"
}
  1. 已编辑public/index.html
<head>
  <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
...

之后,我可以使用从 CDN 加载的 React 在我的库中运行钩子,而 Jest 仍然从 node_modules 加载了 react 副本(从 devDependencies 安装)。

希望有帮助

当我尝试将我的组件从功能组件更改为全类组件时,我遇到了这个问题,我也收到了这个错误,所以这是我关于这个错误的解决方案,希望它对你的情况也有帮助。

在这种情况下尝试使用高阶组件

从“反应”导入反应;
从 'prop-types' 导入 PropTypes;
从“@material-ui/styles”导入 { withStyles };
从'@material-ui/core/Button'导入按钮;

常量样式 = 主题 => ({
根: {
背景:'线性渐变(45度,#FE6B8B 30%,#FF8E53 90%)',
边界:0,
边界半径:3,
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
白颜色',
身高:48,
填充:'0 30px',
},
});

类 HigherOrderComponent 扩展 React.Component {

使成为(){
常量 { 类 } = this.props;
返回 (
高阶分量
);
}
}

HigherOrderComponent.propTypes = {
类:PropTypes.object.isRequired,
};

导出默认 withStyles(styles)(HigherOrderComponent);

我正在使用 Yarn,并通过在我的package.json强制解析来解决此问题:

  "resolutions": {
    "**/react": "16.7.0-alpha.2",
    "**/react-dom": "16.7.0-alpha.2"
  },

您是否添加了 Parent 或 Child 包?

根据上面的一些回复,这对我有用:

  1. 将以下内容添加到config/webpack.config.js
externals: {
  react: {
    root: 'React',
    commonjs2: 'react',
    commonjs: 'react',
    amd: 'react'
  },
  'react-dom': {
    root: 'ReactDOM',
    commonjs2: 'react-dom',
    commonjs: 'react-dom',
    amd: 'react-dom'
  }
}
  1. 已编辑package.json
"devDependencies" : {
  ...
  "react": "^16.9.0",
  "react-dom": "^16.9.0",
}
"peerDependencies": {
  "react": "^16.9.0",
  "react-dom": "^16.9.0"
}
  1. 已编辑public/index.html
<head>
  <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
...

之后,我可以使用从 CDN 加载的 React 在我的库中运行钩子,而 Jest 仍然从 node_modules 加载了 react 副本(从 devDependencies 安装)。

希望有帮助

没有冒犯,但令人不安的是,必须遵循这样的解决方案。 在过去的几天里,我一直试图在不依赖这些黑客的情况下解决这个错误。

我正在开发一个包含使用钩子的组件的可重用库。 在发布它们之前,我需要在实际项目中对其进行测试。 唯一的解决方案是使用yarn|npm link 。 我使用汇总捆绑库,并且可以验证捆绑包不包含反应版本。 当我捆绑(webpack)使用该库的应用程序时,会出现错误/问题。 这也适用于create-react-appnext.js应用程序。 两个框架都在后台使用 webpack。

有没有人找到可持续的解决方案?

通过完全放弃npm|yarn link ,我能够解决问题。 相反,我使用这个可爱的库,它与您的项目结构无关。 它还允许您继续使用 webpack 作为打包器,因此您不必将 _react_ 和 _react-dom_ 声明为externalalias 。 不幸的是,它在项目中引入了一些新目录和锁定文件,但是嘿,它可以在本地甚至在我们的 docker 容器中工作。

也许这对列表有点帮助:

关联

@GabrielBB谢谢,这对我有用

@dmart914谢谢! 到目前为止,唯一对我有用的解决方法:)

目前在使用最小、简单的设置时收到 React Invalid Hook Call 警告。

这个函数组件:

  1. 对 React 和 ReactDOM 使用相同的版本。
  2. 遵循钩子规则。
  3. 只有一份 React。

__依赖项__
反应@16.10.1
反应[email protected]
[email protected]
[email protected]

并运行webpack test.js -o main.js来构建。

我希望这个文件:

  • 渲染盒子。

    • 在调用React.useState之前暂停调试器。

    • 创建一个布尔值test并更新回调updateTest

    • 引发反应错误。

    • 在渲染时执行React.useEffect回调。

    • 引发反应错误。

我做错了什么,还是有其他事情发生?

// test.js
import React, { createElement as el } from 'react';
import ReactDOM from 'react-dom'; 

function Item() {
  debugger;
  const [test, updateTest] = React.useState(false); // Throws React error.

  React.useEffect(function checkTest() { // Throws React error.
    console.log("checking test", test);
  }, [test]);

  React.useEffect(function tester() { // Throws React error.
    if (!test) {
      setTimeout(() => {
        console.log("changing value for test");
        updateTest(true);
      }, 1000);
    }
  }, [test]);

  return el('div', {style: {width: '300px', height: '300px', 'background-color': 'green', border: '1px solid red'}});
}

function render() {
  let root = document.querySelector('#primary');
  if (!root) {
    root = document.createElement('div');
    document.body.appendChild(root);
  }

  ReactDOM.render(Item(), root);
}

render();

你忘了实际创建一个元素。 在到达ReactDOM.render调用之前,您正在同步调用Item() 。 您需要通过el(Item)

真的! 谢谢你的信息。

我的情况与其他一些评论者类似。 我正在使用 webpack 转译一些反应组件(其中一些使用钩子)并将转译后的代码放入lib文件夹中。 我添加了对 webpack 配置的externals字段的响应,因此它不会与组件代码捆绑在一起。 我想在两个单独的项目中使用这些组件——这些组件在它们之间是通用的,所以我们想在一个地方开发它们,并让更新反映在两个应用程序中。

如果在 package.json 中使用common-components: file:../../common-components/lib添加依赖项,那么组件会完美加载,但是运行 webpack 不会立即更新组件 - 相反,我必须运行yarn upgrade common-components然后重新启动开发服务器。

如果使用common-components: link:../../common-components/lib添加依赖项,则重新运行 webpack 将更新主应用程序的node_modules中的文件(因为它现在使用符号链接),但是我收到了多个实例的上述错误做出反应。 我想它现在正在使用common-components/node_modules文件夹中的反应版本。

有没有办法使用符号链接(即common-components: link:../../common-components/lib ),同时确保链接的组件使用主应用程序的 node_modules 文件夹中的反应? 由于我计划在这两个应用程序中使用这些组件,因此我无法将其中一个的 react 包链接到公共组件库中,并且我想避免将两个主要应用程序的 react 链接到公共组件包中使用的一个。 我看到一些评论提到 webpack resolve字段,这听起来很有希望,但我无法让它工作。 任何帮助将不胜感激!

编辑:对于任何对我们的用例感兴趣的人,我们最终更改了构建步骤,只需将文件复制到需要它们的两个项目中,并完全避免转译。

一种快速的解决方法是不发布包,而只需将其推送到 github 并使用yarn add <git-url>将其导入您的项目。

一种快速的解决方法是不发布包,而只需将其推送到 github 并使用yarn add <git-url>将其导入您的项目。

我们中的许多人使用 npm 链接和 npm 包相对路径的原因是开发和测试代码,而无需在我们知道它会起作用之前将更改发布到 NPM 或 GitHub。

我们遇到了与https://github.com/facebook/react/issues/13972#issuecomment -447599035 相关的问题,我认为这也可能是由 Webpack 的节点服务器引起的。 我们的用例是在 Jest 中运行的集成测试,它以编程方式运行webpack()以在执行测试之前构建服务器。 我相信这个问题与 ESM 和 CJS 如何同时存在有关。

以这个例子为例:

// node express server, doing server-rendering
import React from 'react';
import { ApolloProvider } from '@apollo/react-common';
import { renderToStringWithData } from '@apollo/react-ssr';

res.send(await renderToStringWithData(<ApolloProvider><App /></ApolloProvider>)

我在调试器会话中看到的是,我们可以在此文件的编译版本中获得两个不同的 React 实例:

_react: {Children, ...}
_react2: {default: {Children, ...}

在哪里
_react来自此文件中的 ESM import React from 'react'
_react2来自 node_modules/@apollo/react-ssr/lib/react-ssr.cjs.js 内的 CJS var _react = _interopRequireDefault(require("react")); node_modules/@apollo/react-ssr/lib/react-ssr.cjs.js

我相信这会导致在两个地方(服务器渲染文件和@apollo/react-ssr的包内)对 React 的引用不相等,从而导致错误被抛出。

我们发现这可能是由于在测试中以编程方式使用webpack()造成的,并将这些测试重构为端到端测试。 给我们的教训是,如果问题仅发生在测试代码中,那么您的测试可能过于复杂。

我设法用纱线解决了它:

cd 到myApp/node_modules/reactyarn link

然后在你的库中,运行yarn link react

现在您的库正在使用与您的主应用程序完全相同的反应版本

我试图在我的库中将反应设置为对等依赖,但随后库无法构建

如何在不弹出或切换到yarn $ 的情况下使用create-react-app解决此问题?

您可以使用 npm link 使用完全相同的技术。 无需弹出。

当您处理具有不同版本的多个项目时,链接react不是最好的主意。

@woles你是完全正确的,但就我而言,它解决了我的“钩子”问题。 我希望 React 开发人员提出更好的解决方案

你好,
几个小时后我修复了这个错误,意识到我不小心在反应路由器中错误地使用了该组件。

我的应用程序正在运行,但在一个组件中我根本无法添加 useState。 原因是我在 react routers 渲染方法中使用了组件,而没有像这样的高阶函数:
<Route exact path="/path" render={ ComponentCausingTheErrorMesage }/>
切换到
<Route exact path="/path" component={ ComponentNowWorkingAgain }/>
为我修好了

我在应用程序和我正在积极开发的模块之间使用npm link ,我必须通过将应用程序的reactreact-dom链接到模块来修复它,然后链接应用程序的模块:

在应用程序中:

  1. cd node_modules/react && npm link
  2. react-dom相同

在模块中:

  1. npm link react && npm link react-dom
  2. npm link

在应用程序中:

  1. npm link [module-name]

希望这可以帮助某人

我们有钩子在客户端工作,但在 SSR 上遇到了这个错误。 我的同事在我们的服务器端 webpack 配置中通过以下方式解决了这个问题:

const nodeExternals = require('webpack-node-externals');

const serverConfig = () => {
  // lots of config, then:
  externals: [
    nodeExternals({
      modulesFromFile: true,
    }),
  ],
}

我设法用纱线解决了它:

cd 到myApp/node_modules/reactyarn link

然后在你的库中,运行yarn link react

现在您的库正在使用与您的主应用程序完全相同的反应版本

我试图在我的库中将反应设置为对等依赖,但随后库无法构建

这很好用

刚碰到这个问题,同时使用electron-webpack,react和material-ui。 当我尝试使用 material-ui 中的任何内容时 - 我收到此错误(例如尝试使用

嗨 ZVER3D,尝试阅读我之前的评论。 希望能帮助到你!

我在应用程序和我正在积极开发的模块之间使用npm link ,我必须通过将应用程序的reactreact-dom链接到模块来修复它,然后链接应用程序的模块:

在应用程序中:

1. `cd node_modules/react && npm link`

2. same for `react-dom`

在模块中:

1. `npm link react && npm link react-dom`

2. `npm link`

在应用程序中:

1. `npm link [module-name]`

希望这可以帮助某人

亲爱的摩西宝贝,这对我帮助很大。 甚至没有考虑问题是不同版本的反应! 我正在本地构建一个组件以发布到 NPM,但有一个单独的项目在本地使用 npm 链接对其进行测试。 显然(现在)他们都使用不同版本的反应。 哦!

嗨 ZVER3D,尝试阅读我之前的评论。 希望能帮助到你!

感谢您为我指明正确的方向。 另一个解决方案是将我使用的 ui 库添加到“whiteListedModules”中。 唯一的问题是您必须为所有需要 react 编译的模块执行此操作。
所以,在 package.json 我写了这个:

"electronWebpack": {
    "whiteListedModules": [
      "@material-ui/core",
      "@material-ui/icons"
    ]
  }

我正在使用 monorepo 方法开发一个 React 应用程序。 我有一个主应用程序( brush )和一个反应库组件( react-gbajs )。

因此,当我尝试渲染我的react-gbajs组件时,我遇到了关于多个 React 实例的错误。 如果我在brush上复制并粘贴相同的代码,我没有任何问题。
我遵循了许多方法来修复它,但我都没有解决它(更改构建在 Webpack、Yarn 的工作区、npm 链接......)

我尝试调试以检查我是否真的有两个 React 副本(使用 React 文档中的console.log(window.React1 === window.React2) ),但它的评估结果为true
(我现在使用的一个非常糟糕的解决方法是将钩子作为道具传递: <GBAEmulator useEffect={useEffect} /> ...但我真的不想合并它)

任何人都有一些想法来解决它?

我的项目是开源的,我在这个分支中添加了这个新的反应库组件: https ://github.com/macabeus/klo-gba.js/blob/ac18f4d42b122c333622f502947135c2de217ce2/react-gbajs/src/index.js#L251 -L274

大家好,

我有一个应用程序(myApp),它使用自定义库(myDepPackage)作为依赖项。 他们都使用webpack作为构建工具,当然我遇到了同样的错误。 以上解决方案都不适合我。 它所做的是强制 webpack将 react 包含在自定义库(myDepPackage)的最终包中。 我必须添加到 webpack 配置(myDepPackage)的唯一配置行如下:

externals: {
  react: "react",
},

您可以在此处了解有关“externals”选项的更多信息: https ://webpack.js.org/configuration/externals/#externals

@tsevdos Veeeery 谢谢!!! ❤️
它解决了我在上一条评论中所说的问题。

对我们来说,问题在于我们有一个可嵌入的 React 应用程序,它从 WordPress 短代码加载到页面中,并安装在具有随机 ID 的 div 上。 在某些页面上,我们有多个嵌入式应用程序,并且在我们开始使用钩子之前它工作得很好。

它只会抱怨具有多个嵌入式应用程序的页面,因此解决方案是更新 WP 短代码以仅加载一次构建脚本。

听起来简单明了,但要弄清楚却很棘手! 特别是因为在我们添加钩子之前它一直在这样做并且工作正常。

有趣的是,在某些页面上,我们嵌入了其他不同的应用程序,这些应用程序也使用了钩子,它们也使用 React 加载自己的脚本/构建,......但它工作得很好! 问题在于,当它多次加载完全相同的构建并且他们使用 hooks 时

对我有用的是这个问题线程中的两个建议的组合。

主应用程序的 webpack 配置( @apieceofbart建议

  resolve: {
    alias: {
      react: resolve('./node_modules/react')
    }
  }

依赖项的 webpack 配置( @tsevdos建议

  externals:
    react: 'react'
  }

我在使用html-webpack-plugin时遇到了这个问题,并且我使用index.html看起来像这样作为templateHtmlWebpackPlugin设置。

// webpack.config.js
plugins: [
   new HtmlWebpackPlugin({
      template: "./public/index.html"
   })
],
<!-- public/index.html -->
<html>
<head>
    <title>React App</title>
</head>
<body>
    <div id="root"></div>
    <script src="main.js"></script>
</body>

</html>

我意识到插件在 <div id="root"></div> 之后注入<script type="text/javascript" src="main.js"></script> <div id="root"></div>

所以,当我打开开发工具并生成的 html 看起来像这样。

<html>
<head>
    <title>React App</title>
</head>
<body>
    <div id="root"></div>
    <script src="main.js"></script>
    <script type="text/javascript" src="main.js"></script> <!-- injected from html-webpack-plugin -->
</body>

</html>

对我来说,这导致Invalid Hook Call Warning

我可以通过删除<script src="main.js"></script>来删除警告,如下所示。

<!-- public/index.html -->
<html>
<head>
    <title>React App</title>
</head>
<body>
    <div id="root"></div>
</body>

</html>

我希望它可以帮助寻找解决方案的人!

请注意,依赖于 React 的库也可能导致这些问题。 就我而言,我使用了不同版本的@emotion/core@emotion/styled

https://github.com/emotion-js/emotion/issues/1470

你好,

一个不弹出的可能解决方案是将 webpack 别名配置解决方案与 custom -crareact-app-rewired库混合。 这样,您可以通过创建一个 config-overrides.js 文件来覆盖解决问题所必需的 webpack 配置:

const { override, addWebpackAlias } = require('customize-cra');
const path = require('path');

module.exports = override(
  addWebpackAlias({
    react: path.resolve(path.join(__dirname, './node_modules/react')),
  }),
);

我在 Gatsby 网站上遇到了这个问题,我运行 npm install 并更新到最新版本的 Gatsby 并修复了所有问题

如果您在运行yarn or npm test (就像我一样)并使用react-test-renderer时遇到问题,请确保react-test-rendererreact的相同版本匹配您正在使用。

例子:

// Package.json
{
  ...
    "react" : "16.8.3",
  ...
}

运行yarn add [email protected]

我有一个库,我检查了库和主项目中reactreact-dom的所有版本。 它们完全相同,但不起作用。
但是@apieceofbart解决方案对我有用。

@apieceofbart ,你拯救了我的一天 <3

对我有用的是这个问题线程中的两个建议的组合。

主应用程序的 webpack 配置( @apieceofbart建议

  resolve: {
    alias: {
      react: resolve('./node_modules/react')
    }
  }

依赖项的 webpack 配置( @tsevdos建议

  externals:
    react: 'react'
  }

同样在这里。 我需要进行这两个修复才能使其正常工作。 我的解释是,第二个配置告诉依赖项使用名为“react”的外部反应,第一个配置将名称“react”指向主存储库中的“node_modules/react”文件夹。 因此,它们都是使反应桥工作所必需的。

不过,对于某些人来说,其中一个似乎就足够了,我不太明白。

对我有用的是这个问题线程中的两个建议的组合。
主应用程序的 webpack 配置( @apieceofbart建议

  resolve: {
    alias: {
      react: resolve('./node_modules/react')
    }
  }

依赖项的 webpack 配置( @tsevdos建议

  externals:
    react: 'react'
  }

同样在这里。 我需要进行这两个修复才能使其正常工作。 我的解释是,第二个配置告诉依赖项使用名为“react”的外部反应,第一个配置将名称“react”指向主存储库中的“node_modules/react”文件夹。 因此,它们都是使反应桥工作所必需的。

不过,对于某些人来说,其中一个似乎就足够了,我不太明白。

第二条很重要!
如果忽略,在构建过程中,react 将一起导出,因为它是内部依赖项

非常喜欢@apieceofbart !!!! 我正要把我的桌子踢穿墙

因此,微服务仍然没有解决方法。 我有一个带有反应的根应用程序,它动态地需要与另一个反应捆绑在一起。 我们不能只使用外部版本的 react,因为有很多独立的团队有自己的依赖关系。 如果我们推动他们使用相同的外部版本,那么大多数项目显然会崩溃,并且由于每个项目都依赖于这个版本,因此升级这个版本将变得不可能。

有任何想法吗?

是否有将反应钩子与 npm 链接一起使用的解决方案,不需要从 CRA 中弹出?

@tschellenbach
您可以使用 craco 覆盖 CRA 配置而不弹出。
https://github.com/gsoft-inc/craco

感谢@tsevdos ,我已经解决了我的问题并制作了一个关于如何创建 React 包的教程: https ://youtu.be/esyS87NfBOw

我遇到了这个问题并且 webpack 解决方案不适用,因为我使用的是包裹捆绑器。 我可以通过在我的主应用程序的 package.json 中指定一个别名来修复它,看起来像这样

    "alias": {
        "react": "./node_modules/react",
        "react-dom": "./node_modules/react-dom"
    },

尝试在具有不同包 json 的同一项目中的电子应用程序中使用我的 React 组件(用钩子编写)时遇到问题。 文件结构如下所示:

- javascript
  - src
     - ComponentIWantToUse.tsx
      - package.json
- electron
   - src
     - IwantToUseItHere.tsx
      - package.json

package.json 都在 package.json 中包含 react 和 react-dom 但它们是相同的版本,当我执行npm ls react时,我没有看到它显示两个 react 安装。 有任何想法吗?

编辑:@ewan-m 的解决方案奏效了!

所以我遇到了一个奇怪的案例,我想。 不幸的是,第三方库混合了基于功能和类的组件。 我的代码库中的组件可以正常工作。 库中基于类的组件充当将我的组件呈现为子组件的布局。 我相信这是触发“错误:无效的挂钩调用”的原因。 我应该如何解决这个问题才能使用钩子,我需要将我的转换为类组件吗?

@GrandathePanda混合类和功能组件应该无关紧要。 如果一个类调用一个函数,它调用一个钩子,那没有问题。 你唯一不能做的就是直接从类中调用一个钩子。

好的, @JeremyGrieshop那么我还有一些调查要做,如果我在不使用第三方组件的情况下渲染它会很好地渲染,所以那个库和我的代码之间存在一些冲突。 如果我不得不猜测他们可能在他们的包中使用不同的反应版本。

好的, @JeremyGrieshop那么我还有一些调查要做,如果我在不使用第三方组件的情况下渲染它会很好地渲染,所以那个库和我的代码之间存在一些冲突。 如果我不得不猜测他们可能在他们的包中使用不同的反应版本。

对了,从你的应用中检查npm ls react react-dom看看是否有多个版本。 第三方库可能具有特定版本的依赖项。

@JeremyGrieshop所以看起来我的应用程序使用 16.12.0 进行反应和 dom,而第三方(弹性搜索用户界面)使用 16.8.0 进行反应和 dom。 如果我是正确的,那么问题是因为我的 16.8.0 第三方库正在渲染使用 16.12.0 创建的组件,这会导致问题吗? 它们也是一个 lerna monorepo,在阅读完上述所有评论后,这可能会使这进一步复杂化。 这个问题是由在 materialui 中创建的 useStyles 钩子引起的,它们提供了一个 withStyles hoc 以实现向后兼容性,我认为同时我会走这条路。 上面提到的对 webpack 和/或包 json 的所有更改看起来真的像一个创可贴,它更容易被打破,而同时只是使用经典的 hoc,而 hooks 则在面对如此多不同的实现问题时弄清楚如何成熟。

@GrandathePanda恕我直言,您的选择是(1)让第三方将他们的反应依赖更新到 16.12,或者让他们决定将其作为 peerDependency 是否比依赖更合适; (2) 在您的应用程序中使用 16.8,以便它们共享相同的 lib 版本; (3)消除他们的反应副本:

rimraf node_modules/search-ui/node_modules/react && rimraf node_modules/search-ui/node_modules/react-dom

上面的命令可以放在 package.json 的“脚本”部分下的“prebuild”和“prestart”中(这是我目前正在做的)。我想,(3)的缺点是,如果他们正在使用 16.8 和 16.12 之间不推荐使用的任何内容。

大家好,

我有一个应用程序(myApp),它使用自定义库(myDepPackage)作为依赖项。 他们都使用webpack作为构建工具,当然我遇到了同样的错误。 以上解决方案都不适合我。 它所做的是强制 webpack将 react 包含在自定义库(myDepPackage)的最终包中。 我必须添加到 webpack 配置(myDepPackage)的唯一配置行如下:

externals: {
  react: "react",
},

您可以在此处了解有关“externals”选项的更多信息: https ://webpack.js.org/configuration/externals/#externals

@tsevdos我爱你。 你只是结束了几天的激烈麻烦。 谢谢你。

大家好,

我正在尝试在组件中使用挂钩,该组件将从gatsby-browser.js导出。

当前的行为是什么?

我收到此错误:

未处理的拒绝(错误):无效的挂钩调用。 Hooks 只能在函数组件的主体内部调用。 这可能由于以下原因之一而发生:

  1. 你可能有不匹配的 React 版本和渲染器(例如 React DOM)
  2. 您可能违反了 Hooks 规则
  3. 你可能在同一个应用程序中拥有多个 React 副本
    有关如何调试和修复此问题的提示,请参阅https://fb.me/react-invalid-hook-call

这是一个示例代码:

import React from 'react';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';

import configureStore from './src/utils/configure-store';
import { useApiResources } from './src/hooks/use-api-resources';

const RootWrapper = ({ element }) => {
  const resources = useApiResources();
  const store = configureStore();
  return <Provider store={store}>{element}</Provider>;
};

RootWrapper.propTypes = {
  element: PropTypes.node.isRequired,
};

export default RootWrapper;

预期的行为是什么?

Hook 应该在没有错误的情况下运行,或者应该提供有用的错误消息。

react 和 react-dom 依赖的版本是 16.12.0

@leejh3224非常感谢老兄! 经过数小时的搜索,我找到了这个答案,它解决了我的问题。
刚刚更改了 HtmlWebpackPlugin 配置
inject: trueinject: 'head'并且缩小的反应错误消失了。

我用我试图让它工作的经验创建了一个stackoverflow 问题。 对于那些设法让它发挥作用的人来说,是否有可能看看它并提供一些建议?

我正在将一个 jquery 应用程序移植到 React。 我有一个实用程序可以在 jQuery 中公开 React 组件,名为asJqueryPlugin 。 这是文件:

import React from 'react'
import ReactDOM from 'react-dom'

/**
 * A way to render React components with props easily with jQuery
 *
 * ## Register the React Component
 *
 * In your React Component file, register the component with jQuery using `asJqueryPlugin`
 * ```
 * const Greeting = ({ person }) => <div>Hello {person}</div>
 * asJqueryPlugin('Greeting', Greeting, { person: "Bob" })
 * ```
 *
 * ## Rendering, Selecting and Updating Props with jQuery
 *
 * Select an element and render using the `react` function
 * ```
 * $('#greeting').react('Greeting', { person: 'Frank' })
 * ```
 */

window.reactRegistry = window.reactRegistry || {}

// This is how React components register themselves as available within jQuery
export default function asJqueryPlugin(componentName, Component) {
  window.reactRegistry[componentName] = { Component }
}

if (typeof window.$ !== 'undefined') {
  ;(function($) {
    // Add the plugin function jQuery
    $.fn.react = function renderReactIntoElements(componentName, props) {
      this.each(function render() {
        const entry = window.reactRegistry[componentName || $(this).data('react')]
        if (!entry) throw Error(`${componentName} component is not registered.`)
        ReactDOM.render(<entry.Component {...props} />, this)
      })
      return this
    }
  })(window.$)
}

该应用程序在 Webpack 中有许多入口点,现在大约有 3-4 个组件正在使用这种技术。 当组件被捆绑到不同的入口点捆绑包中时,我相信这就是问题发生的时候。

因此,如果我在 Webpack 中有两个入口点:

entry: {
      foo: './assets/js/foo',
      bar: './assets/js/bar'
}

然后在每个文件中,我们设置一个公开的组件(每个都使用钩子):

// foo.js
import React from 'react'
import asJqueryPlugin from '../utils/asJqueryPlugin'
const Foo = () => {
  const ref = useRef()
  return <div ref={ref}>Foo</div>
}
asJqueryPlugin('Foo', Foo)

// bar.js
... same stuff but with Bar component

现在,如果我在同一页面上包含两个条目,并尝试通过 jquery 插件呈现这两个组件...

<script src="/bundles/foo.js" />
<script src="/bundles/bar.js" />
<script>
    $('#foo-container').react('Foo')
    $('#bar-container').react('Bar')
</script>

...我得到这个钩子错误。

不确定这是否有助于对话,但至少展示了一个用例,说明(可能)理智的开发人员如何让自己陷入具有多个反应实例的情况。

这对我有帮助 - https://github.com/facebook/react/issues/13991#issuecomment -554928373
但我还必须从依赖项中删除reactreact-dom并将它们移动到对等依赖项并卸载并重新安装节点模块。

你好,
我阅读了网络上的对话和许多帖子,但我仍然遇到多个反应实例的错误。
我推送此 repo 以重现错误: https ://github.com/jeromelegrand/dooliz-lib
我希望有一个人可以帮助我。
谢谢。

我面临这个问题,并且无法通过上述解决方案获得任何帮助。
简而言之:我很确定我只有一个反应版本在运行,并且我使用 react-bootstrap 得到错误,它可能没有使用错误的钩子,因为没有其他人有问题。

这个错误发生在我的 node.js 后端。

__我检查了反应版本__

我有一个带有工作区的纱线设置, yarn list reactyarn list react-dom只显示一个实例。

我已经打印了 require cache 以查看已导入的内容:

for(var key in require.cache) {
    if(key.indexOf("react") !== -1 && key.indexOf("index") !== -1) {
        console.log(key);
    }
}

我在从 react-bootstrap 渲染某些东西之前运行它,这对我来说会导致无效的钩子错误,它会记录:

C:\web\resourceful\daCore\node_modules\react-dom\index.js
C:\web\resourceful\daCore\node_modules\react\index.js
C:\web\resourceful\daCore\node_modules\react-router-dom\index.js
C:\web\resourceful\daCore\node_modules\react-router-dom\node_modules\react-router\index.js
C:\web\resourceful\daCore\node_modules\react-is\index.js
C:\web\resourceful\daCore\node_modules\mini-create-react-context\dist\cjs\index.js
C:\web\resourceful\daCore\node_modules\react-router\index.js
C:\web\resourceful\daCore\node_modules\@fortawesome\react-fontawesome\index.js
C:\web\resourceful\daCore\node_modules\@tinymce\tinymce-react\lib\cjs\main\ts\index.js

这似乎证实只加载了 1 个反应版本。

最后我把它添加到 node_modules/react-dom/index.js

console.log("React DOM daCore");
global['React1'] = require('react');

这到 node_modules/react-router-dom/cjs/Form.js

require('react-dom');
global['React2'] = require('react');
console.log('#TEST '+(global['React1'] === global['React2']? 'SAME' : 'NOT SAME'));

打印SAME

知道这还能是什么吗?
我也会在 react-bootstrap repo 上发布这个。

所以我很确定拥有两个 React 实例不是这里的问题。 我认为问题在于当有两个反应_roots_。 您是否在页面的不同部分多次调用ReactDOM.render() ? 如果是这样,我认为这可能会导致问题。 我认为钩子“属于”特定的“根”,并且当它们有多个并且两个捆绑包共享一些公共代码时会中断。 我猜这里...

...我认为问题是当有两个反应_roots_。 您是否在页面的不同部分多次调用ReactDOM.render()

谢谢@timkindberg ,这帮助我最终解决了这个问题。 我意识到我正在使用react-tree-walker进行初始渲染并获取所需的数据,然后再使用ReactDOMServer.renderToString进行最终渲染

快速删除这个包的使用消除了错误,我现在已经有了与react-ssr-prepass相同的东西,实际上现在在 react-tree-walker 自述文件页面上推荐

所以这确实是两个ReactDOM.render调用! 现在这个带有react-ssr-prepass 的设置对我有用,当 Suspense 进入 react-dom/server 时,我可以切换到那个

我在我的 Gutenberg 项目中使用react-compare-image https://github.com/junkboy0315/react-compare-image ,但是有这个奇怪的问题,尽管每当我从保存功能中删除ReactCompareImage组件时一切正常。 编辑功能完美,但保存不起作用。

我浏览了https://reactjs.org/warnings/invalid-hook-call-warning.html并且我不认为,我有任何这些问题。

这是完整的保存功能文件:

```从“./inspector”导入检查器;
从“反应”导入{片段};
从“react-compare-image”导入 ReactCompareImage;

/**

  • WordPress 依赖项
    */
    常量 {__} = wp.i18n;

const save = ({className, attributes}) => {

const {
    paddingTop,
    paddingRight,
    paddingBottom,
    paddingLeft,

    marginTop,
    marginRight,
    marginBottom,
    marginLeft,

    border,
    borderColor,
    borderType,
    background,

    backgroundImage,
    gradient,

    dividerColor,
    buttonColor,

    direction,

    beforeImage,
    beforeLabel,
    afterImage,
    afterLabel,

} = attributes;

const style = {
    "padding": `${paddingTop}px ${paddingRight}px ${paddingBottom}px ${paddingLeft}px`,
    "margin": `${marginTop}px ${marginRight}px ${marginBottom}px ${marginLeft}px`,
    "border": `${border}px ${borderType} ${borderColor}`,
    "background": background
};

return(
    <Fragment>
        <ReactCompareImage
            leftImage={beforeImage.url}
            leftImageLabel={beforeLabel}
            rightImage={afterImage.url}
            rightImageLabel={afterLabel}
            vertical={'vertical' === direction}
            sliderLineColor={dividerColor}
        />
    </Fragment>
);

};

导出默认保存;
```
Screenshot 2020-02-19 at 4 11 52 PM

我也遇到了这个问题。 我在 SO 上发布了一个回顾: https ://stackoverflow.com/questions/60331304/next-js-with-typescript-invalid-hook-call-hooks-can-only-be-called-inside-of-t

我还有一个最小的可重现示例: https ://github.com/coler-j/shopify_playground

我的主应用程序是一个create-react应用程序(未弹出),它正在导入一个也使用 React 的共享库。 我能够通过以下方式解决此问题:

使用 Rollup 打包库而不是 webpack
出于某种原因,我还没有解决,使用外部并没有从库包中删除 React。

汇总-config.js

export default [
  {
    input: 'src/index.js',
    output: {
      file: pkg.main,
      format: 'cjs',
      sourcemap: true,
    },
    plugins: [external(), babel(), resolve(), commonjs(), svgr()],
  },
  {
    input: 'src/index.js',
    output: {
      file: pkg.module,
      format: 'es',
      sourcemap: true,
    },
    plugins: [
      alias({
        entries: [{ find: '<strong i="12">@components</strong>', replacement: 'src/components' }],
      }),
      external(),
      babel(),
      svgr(),
    ],
  },
]

安装 craco 并使用它来修改主应用程序的 webpack
craco.config.js

const path = require('path')

module.exports = {
  webpack: {
    alias: {
      react: path.resolve(__dirname, './node_modules/react'),
    },
  },
}

感谢@arminyahya将我指向craco。

我试图在从 CDN 加载反应时使用钩子。 这个例子(这是整个 html 页面)在调用Example()时给出了Hooks can only be called inside of the body of a function component错误。 我已经删除了所有内容,甚至是 ReactDOM,所以很难想象我可以拥有多个 React 副本。 这是不可能的吗?

<!DOCTYPE html>
<html>

<head>
  <script crossorigin src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>

</body>
  <script type="text/babel">
    function Example() {
      let [count, setCount] = React.useState(0);
      return ( <h1>Hello</h1> );
    };

  Example();
  </script>
</body>

</html>

@samkamin那是因为你有零反应根。 您需要呈现您的应用程序。 但是,这仍然是一个很好的确认,即 hooks 依赖于(并耦合到)react root。

<html>
<head>
  <script crossorigin src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
  <script crossorigin src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
</body>
  <div id="root"></div>
  <script type="text/babel">
    function Example() {
      let [count, setCount] = React.useState(0);
      return ( <h1>Hello</h1> );
    };

    ReactDOM.render(<Example />, document.getElementById('root'))
  </script>
</body>
</html>

谢谢! 实际上并不是缺少反应根——我只是在尽可能简化错误的过程中删除了它——但同样愚蠢的东西:我只是写了<Example />而不是Example() 。 根本不是一回事。 再次感谢。

似乎没有什么对我有用。 我正在创建一个组件以在其他项目中共享和使用,但是在从另一个项目进行本地测试时不起作用。 我正在使用带有反应 16.13.0 的 Hooks。

webpack.config.js

module.exports = {
  entry: ENTRY,
  output: {
    library: LIBRARY_NAME,
    path: path.resolve(__dirname, OUTPUT_DIR),
    filename: OUTPUT_FILENAME,
    libraryTarget: 'commonjs2',
  },
  module: {
    rules: [
      {
        test: /\.(js|tsx)$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      },
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: 'ts-loader',
      },
    ],
  },
  resolve: {
    alias: {
      '<strong i="7">@src</strong>': path.resolve(__dirname, './src'),
      '<strong i="8">@components</strong>': path.resolve(__dirname, './src/components'),
      '<strong i="9">@core</strong>': path.resolve(__dirname, './src/core'),
      react: path.resolve(__dirname, './node_modules/react'),
      'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
    },
    extensions: ['.js', '.json', '.tsx', '.ts'],
  },
  externals: {
    react: 'react',
  },
  target: 'node',
  plugins: [
    new HtmlWebPackPlugin({
      template: './tests/index.html',
      filename: 'index.html',
    }),
  ]}

有什么建议? 我测试了旧讨论的所有建议。
谢谢! :咧嘴笑:

我声明了一个 Settings.js 如下:

import React, {useState} from 'react';

import {
    View,
    Text,
    Switch
} from 'react-native';

export function Settings(props) {
    const [rememberPin, setRememberPin] = useState(false);
    let {changeView, header} = props;


    const toggleRememberPin = (value) => {
        setRememberPin(value);
    };

    return (
            <View>
                    <Text>Remember PIN:</Text>
                    <Switch
                        onValueChange={toggleRememberPin}
                        value={rememberPin}
                        ios_backgroundColor="#aeaeae"
                        />
            </View>
    );
}

export default {Settings};

我在 App.js 中导入并使用它,如下所示:

import React, {Component} from 'react';
import {
    SafeAreaView,
    StyleSheet,
    View,
    Text,
    TouchableOpacity,
    Dimensions,
    ScrollView,
    Switch
} from 'react-native';

import Colors from './src/assets/Colors';
import {Settings} from './src/components/Settings';
...

export default class App extends Component {
    constructor(props) {
        super(props);
        this.state = {viewsStack: this.viewsStack};
    }

    viewsStack = {
        SplashScreen: false,
        BindingInstructions: false,
        PinPad: false,
        Qr: false,
        Dashboard: false,
        Authorizations: false,
        Settings: true,
        Browsers: false,
        TransmitSDK: false,
        OTP: false,
    };

    changeView = (newView) => {
        let {viewsStack} = this.state;
        for (let key of Object.keys(viewsStack)) {
            viewsStack[key] = false;
        }
        viewsStack[newView] = true;
        this.setState(viewsStack);
    };

    render() {
        let {viewsStack} = this.state;
        return (
            <SafeAreaView style={styles.safeAreaView}>
                {viewsStack.SplashScreen && (splashScreen())}
                {viewsStack.BindingInstructions && (bindingInstructions({changeView: this.changeView}))}
                {viewsStack.PinPad && (pinPad({message: 'Inserisci un nuovo PIN', changeView: this.changeView}))}
                {viewsStack.Qr && (qr({header: 'QR Binding', message: 'Scansiona il QR dalla tua dashboard\noppure\ninserisci il codice manualmente.', changeView: this.changeView}))}
                {viewsStack.Dashboard && (dashboard({header: 'Profilo Utente', changeView: this.changeView}))}
                {viewsStack.Authorizations && (authorizations({header: 'Autorizzazioni', authorizations: [1, 2, 3, 4, 5, 6], changeView: this.changeView}))}
                {viewsStack.Settings && (Settings({header: 'Impostazioni', changeView: this.changeView}))}
            </SafeAreaView>
        );
    }
};
...

但我得到:

Screenshot 2020-02-27 at 22 27 01

我在用:

"react": "16.9.0",
"react-native": "0.61.5"

怎么了?

您将Settings组件称为函数而不是函数组件。

<Settings header='Impostazioni' changeView={this.changeView} />

在普通函数中不允许使用钩子,只有在函数组件中才允许使用钩子,并且您调用它的方式会欺骗 React 认为您的组件实际上是一个普通函数。

也许这会让别人头疼,如果你使用 react-router-dom 如果你像这样在渲染中传递你的组件(不是正确的方式)它会给出Invalid Hook Call Warning
<Route path="/:cuid/:title" render={PostArticle} />

花了我半个小时才知道我哪里错了

这可能对某人有所帮助 - 如果您在使用 react-router-dom 后遇到此错误,请检查您是如何定义路由的。 例如,当我在做<Route path={'/upgrade/:plan'} exact children={Upgrade} />时,它应该是<Route path={'/upgrade/:plan'} exact children={<Upgrade />} /> #$

如果您使用墨水蜡笔来构建 CLI,这尤其尴尬(请参阅 https://github.com/vadimdemedes/pastel/issues/2)。 我不能让它成为 peerDep,因为我不能要求每个用户都安装 React,我也不能强迫他们使用某个版本/范围的 React。

我的团队正在使用 Yarn,并且仅在测试中而不是在应用程序中收到Invalid hook call错误。 问题是react-test-renderer正在解析为低于reactreact-dom的版本,因此我们在package.json中添加resolutions #$ :

"devDependencies": {
    ...
    "react": "16.12.0",
    "react-dom": "16.12.0",
    ...
},
"resolutions": {
    "react-test-renderer": "16.12.0"
}

对于在子目录中使用 Gatsby 的人来说,这是一个可能的解决方案。

gatsby-node.js :

const path = require('path')
const fromRoot = name => path.resolve(__dirname + '/../node_modules/' + name)

exports.onCreateWebpackConfig = ({ actions }) => actions.setWebpackConfig({
  resolve: {
    alias: {
      'react': fromRoot('react'),
      'react-dom': fromRoot('react-dom'),
    },
  },
})

我在执行npm link命令时遇到同样的问题,有问题

然后我用react官方提供的解决方案解决了这个问题

当您使用 npm link 或等效项时,也会出现此问题。 在这种情况下,你的打包器可能会“看到”两个 React——一个在应用程序文件夹中,一个在你的库文件夹中。 假设 myapp 和 mylib 是同级文件夹,一种可能的解决方法是从 mylib 运行 npm link ../myapp/node_modules/react。 这应该使库使用应用程序的 React 副本。

如果 A 需要介绍 B (A 和 B 是兄弟姐妹)

  • 第 1 步(在 B 中)

    • npm link ./../A/node_modules/react

    • npm link

  • 第 2 步(在 A 中)
    npm link B

这个对我有用

即使有了这些答案,我也不确定为什么会出现错误。 我将我的依赖库链接到我的主应用程序,在我收到错误后,我按照 react-docs 并将我的依赖库的 react 版本链接到我的应用程序的 react (运行npm link <>/webapp/node_modules/react 。(甚至使用 react- dom). 当我登录测试 React1 和 React2 是否相同时,它记录true所以我没有使用 React 的重复版本,我使用的是相同版本的 React,并且我使用的是函数组件. 因此,即使测试日志表明我没有 React 的重复版本,我仍然收到钩子错误。

但是如上所述尝试此解决方案修复了该特定错误:

alias: {
        react: path.resolve('./node_modules/react')
 }

所以我很茫然。

所以我很茫然。

@orpheus您是否将多个反应根渲染到同一页面中? aka 您在同一页面上是否有多个ReactDOM.render调用?

您是否将多个反应根渲染到同一页面中? aka 您在同一页面上是否有多个ReactDOM.render调用?

@timkindberg

我不。 我的ReactDOM.render位于我的app的根目录下,我链接的lib模块是一个组件库,不使用ReactDOM.render一点也不。

编辑:我正在做类似于:

import React from 'react'
import ReactDOM from 'react-dom'
import Root from './App/Root'

ReactDOM.render(
  <Root />,
  document.getElementById('root')
)

其中<Root />呈现类似

const Root = () => {
  return <Provider store={store}>
        <PermissionsProvider>
              <Suspense fallback={null}>
                <Router history={history}>
                  <Routes store={store} />
                </Router>
              </Suspense>
        </PermissionsProvider>
  </Provider>
}

PermissionsProvider是我从链接的lib模块导入的 React 组件,它使用了一个导致应用程序失败的钩子。 它创建状态和上下文并呈现它的孩子。

嗨,我正在使用带有反应钩子的电子。 如果我编写自己的钩子,它会起作用。 但是当我在 node_module 中使用其他包中的钩子时,它会抛出错误,比如react-useswr

我必须将包复制到我的本地文件。

有人遇到这个问题吗?

这里的示例项目:
https://github.com/Zaynex/electron-react-ts-kit/tree/hooks-error

核心代码:
https://github.com/Zaynex/electron-react-ts-kit/blob/hooks-error/src/renderer/app.tsx

即使删除了 react 和 react-dom 的重复副本,我仍然遇到这个问题。 我创建了一个超级简单的测试项目来重现。

$ tree -I node_modules
.
|-- test-app
|   |-- dist
|   |   |-- index.html
|   |   `-- main.js
|   |-- package-lock.json
|   |-- package.json
|   |-- src
|   |   |-- index.html
|   |   `-- index.js
|   `-- webpack.config.js
`-- test-lib
    |-- dist
    |   `-- main.js
    |-- package-lock.json
    |-- package.json
    |-- src
    |   `-- index.js
    `-- webpack.config.js

目前,我正在使用 webpack 别名方法,但我也尝试了npm link方法,但都不起作用。

我也遇到过这个问题。 我正在使用 ExpressJS + Pug 来渲染视图,然后我编写了一个渲染器(类似于 ReactRails),它允许您在服务器端和客户端渲染组件。

我试图将它提取到一个单独的包中,因为它变得混乱,我遇到了这个问题。

为了修复它,我必须在resolve键下添加:

alias: {
  react: path.resolve("./node_modules/react"),
},

它现在在正常运行 webpack 时按预期工作,但问题仍然存在于 docker 卷上。 我对 docker 太陌生,无法处理它,所以稍后会重新审视它。

编辑:我说得太早了。 它现在可以在 React 渲染中正常工作,但不适用于 hydra。

嗨,我正在使用带有反应钩子的电子。 如果我编写自己的钩子,它会起作用。 但是当我在 node_module 中使用其他包中的钩子时,它会抛出错误,比如react-useswr

我必须将包复制到我的本地文件。

有人遇到这个问题吗?

这里的示例项目:
https://github.com/Zaynex/electron-react-ts-kit/tree/hooks-error

核心代码:
https://github.com/Zaynex/electron-react-ts-kit/blob/hooks-error/src/renderer/app.tsx

你好。 我遇到过同样的问题。 我正在使用 electron-webpack 将所有模块标记为 webpack 的外部。 几乎没有硬编码的异常——比如 react 和 react-dom。
对我来说,这意味着从我的代码加载的反应与从此类模块加载的反应不同。
将这些模块添加到白名单似乎有所帮助(不确定它是否还没有破坏其他任何东西:)

@huhle谢谢,它有效! 也许我们应该深入研究 electron-webpack。

我只是设法让这个工作自己。 对于 Lerna 和 Yarn 工作空间,我认为这是更好的解决方案之一,也许其中一些部分可以用于另一种解决方案。

这一切似乎都归结为我正在导入的package.json项目的配置。 我需要包括这些部分:

 "peerDependencies": {
    "react": "^16.13.1",
    "react-dom": "^16.13.1"
  },
  "workspaces": {
    "nohoist": [
      "react", "react-dom"
    ]
  }

完成此操作后,我必须重新构建项目,然后开始运行。 似乎将它们列为对等依赖项允许它们被您的消费项目安装。 并且因为它们没有在依赖项中列出,所以它们不应该对您尝试导入的包可用,但是由于某种原因,除非您告诉它不要提升,它们仍然可用并且新的反应实例进入并且导致错误。

祝你好运!

我正在尝试使用 react-spring 来获得简单的淡入效果。 似乎没有任何工作。
`从'react'导入反应,{useState,useEffect};
从'react-spring'导入{动画,useTransition};

const TextContent = (props) => {

const [items] = useState([
    { id: '0', title: 'Text1' },
    { id: '1', title: 'Text2' },
    { id: '2', title: 'Text1' }
])

const [index, setIndex] = useState(0);

const transitions = useTransition(items[index], index => index.id,
    {
        from: { opacity: 0 },
        enter: { opacity: 1 },
        leave: { opacity: 0 },
        config: { tension: 220, friction: 120 }
    }
)

useEffect(() => {
    const interval = setInterval(() => {
        setIndex((state) => (state + 1) % items.length);
    }, 4000)
    return () => clearInterval(interval);
}, []);

return (
    <div>
        {
            transitions.map(({ item, props, key }) => (
                <animated.div
                    key={key}
                    style={{ ...props, position: 'absolute' }}
                >
                    <p>{item.title}</p>
                </animated.div>
            ))
        }
    </div>
)

}

导出默认文本内容;`
Capture

我尝试检查我是否有多个 React 实例。 Npm ls-ing 告诉我我只有一个版本的 react 和 react-dom,这两个版本都在 16.13.1。

嗨,我正在使用带有反应钩子的电子。 如果我编写自己的钩子,它会起作用。 但是当我在 node_module 中使用其他包中的钩子时,它会抛出错误,比如react-useswr
我必须将包复制到我的本地文件。
有人遇到这个问题吗?
这里的示例项目:
https://github.com/Zaynex/electron-react-ts-kit/tree/hooks-error
核心代码:
https://github.com/Zaynex/electron-react-ts-kit/blob/hooks-error/src/renderer/app.tsx

你好。 我遇到过同样的问题。 我正在使用 electron-webpack 将所有模块标记为 webpack 的外部。 几乎没有硬编码的异常——比如 react 和 react-dom。
对我来说,这意味着从我的代码加载的反应与从此类模块加载的反应不同。
将这些模块添加到白名单似乎有所帮助(不确定它是否还没有破坏其他任何东西:)

杰出的! 谢谢

我正在尝试使用 react-spring 来获得简单的淡入效果。 似乎没有任何工作。
`从'react'导入反应,{useState,useEffect};
从'react-spring'导入{动画,useTransition};

const TextContent = (props) => {

const [items] = useState([
    { id: '0', title: 'Text1' },
    { id: '1', title: 'Text2' },
    { id: '2', title: 'Text1' }
])

const [index, setIndex] = useState(0);

const transitions = useTransition(items[index], index => index.id,
    {
        from: { opacity: 0 },
        enter: { opacity: 1 },
        leave: { opacity: 0 },
        config: { tension: 220, friction: 120 }
    }
)

useEffect(() => {
    const interval = setInterval(() => {
        setIndex((state) => (state + 1) % items.length);
    }, 4000)
    return () => clearInterval(interval);
}, []);

return (
    <div>
        {
            transitions.map(({ item, props, key }) => (
                <animated.div
                    key={key}
                    style={{ ...props, position: 'absolute' }}
                >
                    <p>{item.title}</p>
                </animated.div>
            ))
        }
    </div>
)

}

导出默认文本内容;`
Capture

我尝试检查我是否有多个 React 实例。 Npm ls-ing 告诉我我只有一个版本的 react 和 react-dom,这两个版本都在 16.13.1。

同样在这里。 react 和 react-dom 对我来说是 16.13.1,尝试使用 react-spring 会带来同样的错误。

styled-components的另一个线程中,我了解到,如果您通过 $#$ package.json $#$ 中的file: URI 使用自己的本地包,则需要rm -rf node_modules/local-package-name/node_modules在运行您的应用程序之前,因为显然,本地包被复制而不检查node_modules是否存在冗余依赖项。

styled-components的另一个线程中,我了解到,如果您通过 $#$ package.json $#$ 中的file: URI 使用自己的本地包,则需要rm -rf node_modules/local-package-name/node_modules在运行您的应用程序之前,因为显然,本地包被复制而不检查node_modules是否存在冗余依赖项。

是的,仅在这个线程中就大约有十几个用例存在同样的问题。 我添加了一个“prestart”和“prebuild”目标来执行 rm -rf(使用 rimraf)。 该线程中的另一个用户在他们的 prestart 中使用了 npm-link-shared 来让模块共享相同的 react 实例。 我们很多monorepo用户都遇到了这个问题。

嗨,我正在使用带有反应钩子的电子。 如果我编写自己的钩子,它会起作用。 但是当我在 node_module 中使用其他包中的钩子时,它会抛出错误,比如react-useswr
我必须将包复制到我的本地文件。
有人遇到这个问题吗?
这里的示例项目:
https://github.com/Zaynex/electron-react-ts-kit/tree/hooks-error
核心代码:
https://github.com/Zaynex/electron-react-ts-kit/blob/hooks-error/src/renderer/app.tsx

你好。 我遇到过同样的问题。 我正在使用 electron-webpack 将所有模块标记为 webpack 的外部。 几乎没有硬编码的异常——比如 react 和 react-dom。
对我来说,这意味着从我的代码加载的反应与从此类模块加载的反应不同。
将这些模块添加到白名单似乎有所帮助(不确定它是否还没有破坏其他任何东西:)

这也适用于在使用 redux 或 redux 工具包和 electron-webpack 时遇到问题的人。 我有以下工作配置:

// package.json
...
"electronWebpack": {
  "whiteListedModules": ["react-redux"]
}

https://github.com/electron-userland/electron-webpack/issues/349

我的问题是我写的

import React from 'React'

代替:

import React from 'react'

有时是愚蠢的事情。

我通过在我的 webpack 配置中添加以下内容来解决它:

 externals: {
    react: {
      root: "React",
      commonjs2: "react",
      commonjs: "react",
      amd: "react",
    },
    "react-dom": {
      root: "ReactDOM",
      commonjs2: "react-dom",
      commonjs: "react-dom",
      amd: "react-dom",
    },
  },

我一开始以为是 npm link 的问题,按照建议做了,甚至改用了 yarn。 最终发现当发布到 npm 时发生了其他事情,在导入另一个项目时出现了同样的错误。

有没有人最近用 lerna monorepo 解决了这个问题? 我已经尝试了一些没有运气的建议。

添加下面用 // 注释掉的代码后遇到错误。 添加 CssBaseline 和反应片段信息会导致错误。 当它被注释掉时,一切都运行良好。 原始代码只是基本的 npx create-react-app 代码。 对此完全陌生,我从上面尝试的一些修复没有效果。

从“反应”导入反应;
从'./logo.svg'导入标志;
从“@material-ui/core/CssBaseline”导入 CssBaseline;

导出默认函数 App() {
返回 (

        //<React.Fragment>

        //<CssBaseline />

        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo" />
                <p>
                    Edit <code>src/App.js</code> and save to reload.
                    </p>
                <a
                    className="App-link"
                    href="https://reactjs.org"
                    target="_blank"
                    rel="noopener noreferrer"
                >
                    Learn React
                    </a>
            </header>
        </div>

    //</React.Fragment>

);
}

对于本地测试:
在库 node_modules 中删除 react 和 react-dom 文件夹
在主包中再次运行“yarn install”或“npm install”。

这可以防止 react 的第二个副本被加载到主包中。 显然不是永久性修复,但适用于本地测试。

对于任何使用 lerna 的人,在一个包中运行测试时,您可能会遇到这个问题,其中代码引用了另一个包中的组件。

我们在这种情况下遇到的问题是由于 react 被导入到规范中,并且还被导入到组件树中使用Material UI 的 withStyles的组件中,该组件是使用 Material UI 中的钩子实现的。

似乎反应在内部管理ReactCurrentDispatcher.current变量中的状态,这最终在反应的一个实例中设置,但在反应的另一个实例中使用 - 当它为空时,它抛出Invalid hook call ...消息。

我们已经在构建时使用Craco来覆盖 Create React App 的 webpack 配置:

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

然而,这个 webpack 覆盖只在构建时使用——在运行测试时,代码不是构建的,而是从源代码实例化的——所以我们的解决方案是在我们的craco.config.js中使用CracoAlias来指定测试期间的反应路径:

  plugins: [
    {
      plugin: CracoAlias,
      options: {
        source: 'options',
        baseUrl: './',
        aliases: {
          // We need to alias react to the one installed in the desktop/node_modules
          // in order to solve the error "hooks can only be called inside the body of a function component"
          // which is encountered during desktop jest unit tests,
          // described at https://github.com/facebook/react/issues/13991
          // This is caused by two different instances of react being loaded:
          // * the first at packages/desktop/node_modules (for HostSignUpDownloadComponent.spec.js)
          // * the second at packages/components/node_modules (for packages/components/Modal)
          react: './node_modules/react',
        },
      },
    },
  ],

按照@apieceofbart的示例,我使用@craco/craco作为解决方案,没有弹出。 对我来说,使用npm link对本地模块进行测试的步骤如下:

  1. 通过运行npm i @craco/craco --save将 craco 安装到我的演示应用程序
  2. 将配置文件craco.config.js创建到 package.json 位于演示应用程序中的根目录。
  3. 通过在我的演示应用程序中将react-scripts替换为craco来更改startbuildtest脚本。
// craco.config.js
const path = require('path');

module.exports = {
    webpack: {
        alias: {
            react: path.resolve(__dirname, './node_modules/react')
        }
    }
}
// package.json
{
....
"scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "react-scripts eject"
  },
...
}

编辑:我什至没有注意到@jasondarwin有同样的想法。

花了一天的时间试图解决这个问题。 在这里发布我的解决方案,以防它帮助任何人。

我们正在使用一个 monorepo,两个包从 react 导入不同的实例,但它们解析到根节点模块中的同一个位置。 原来我们有这两个实例,因为其中一个应用程序使用它自己的 webpack 来创建一个包。 这被正确地提升到根节点模块,但在由该包导入时会获得它自己的实例。 解决方案是在 webpack 配置的外部包含 react 和 react DOM,这样 webpack 就不会为包创建新的 react 实例。

externals: { react: 'react', reactDOM: 'react-dom', },

希望这对某人有帮助!

对我来说,它使用的是 react-hot-loader 版本 4.0.0,更新到 react-hot-loader 4.8 似乎可以解决问题

只有在我为使用模态窗口而创建的自定义 Hook 上运行测试时,我才会收到Invalid hook call消息。

为了演示这种行为,我在下面创建了一个示例:
(https://github.com/BradCandell/invalid-hook-example)

  • 只有一个版本的reactreact-dom

我错过了一些非常明显的东西吗? 当我过去违反规则时, npm start会失败。 但这只是在我的测试中失败。

感谢您的帮助!
-布拉德

我通过在我的 webpack 配置中添加以下内容来解决它:

 externals: {
    react: {
      root: "React",
      commonjs2: "react",
      commonjs: "react",
      amd: "react",
    },
    "react-dom": {
      root: "ReactDOM",
      commonjs2: "react-dom",
      commonjs: "react-dom",
      amd: "react-dom",
    },
  },

我一开始以为是 npm link 的问题,按照建议做了,甚至改用了 yarn。 最终发现当发布到 npm 时发生了其他事情,在导入另一个项目时出现了同样的错误。

这为我修好了。 我正在导入 react-toastify 并收到无效的钩子调用。 我浏览了控制台错误中的每个项目:

  1. 你可能有不匹配的 React 和 React DOM 版本。

    1. 您可能违反了 Hooks 规则。

    2. 您可能在同一个应用程序中拥有多个 React 副本。

最终成为第 3 期。 我跟着这个:
https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate -react

上面的解决方案都不适合我,直到我意识到我正在将另一个 react 副本与我正在_importing_的库捆绑在一起。
我已经编译并捆绑了我的库的源代码,因此检查文档中列出的不同版本的 React 是返回true而不是false
react标记为外部依赖项并将其从我的库的捆绑包中删除就可以了。

我的案例不是monorepo,而是有点类似的情况。 我们正在开发一个新的 UI 框架,而不是使用 npm link 或 lerna 我们只是使用 webpack 别名来要求同级文件夹中的文件。 它工作正常,但你会遇到这个问题。 幸运的是, @apieceofbart的解决方案为我们解决了这个问题。

第 130:21 行:在函数“pharmacyDashboard”中调用 React Hook “useStyles”,该函数既不是 React 函数组件,也不是自定义 React Hook 函数 react-hooks/rules-of-hooks
第 133:45 行:React Hook "React.useState" 在函数 "pharmacyDashboard" 中被调用,它既不是 React 函数组件也不是自定义 React Hook 函数 react-hooks/rules-of-hooks

这是错误.....谁能帮我解决这个问题

@vyshnaviryali你最好调用你的函数usePharmacyDashboard

./src/components/HomeFiles/AppFooter.js
第 1:1 行:未找到规则“material-ui/no-hardcoded-labels”的定义 material-ui/no-hardcoded-labels'
谁能帮我解决这个问题

对于使用npm link运行此问题的每个人,因为您需要在组件中添加功能但不想在测试之前使用 $ npm publish ,我很惊讶没有人建议使用yalc (https://www.npmjs.com/package/yalc)

对于使用npm link运行此问题的每个人,因为您需要在组件中添加功能但不想在测试之前使用 $ npm publish ,我很惊讶没有人建议使用yalc (https://www.npmjs.com/package/yalc)

我去年确实做过: https ://github.com/facebook/react/issues/13991#issuecomment -535150839

我们已经使用它快一年了,没有任何问题。

另一个在这里使用 lerna; 为了解决这个问题,我将reactreact-dom依赖项移动到我的根目录package.json

我有同样的问题,我通过添加解决了它:

 alias: {
        react: path.resolve('./node_modules/react')
      }

到我的主应用程序的 webpack 配置中的resolve属性。

使用两个 React 副本显然是我的错误,但我同意如果错误消息更好,那就太好了。 我认为这可能类似于:#2402

对于那些使用上述方法但在运行 jest 时仍然出现错误的用户,请将这些添加到 jest 配置中的moduleNameMapper中(如果不需要,请忽略 react-dom):

moduleNameMapper: {

...

  "^react$": "<rootDir>/node_modules/react",
  "^react-dom$": "<rootDir>/node_modules/react-dom",

...

}

我不知所措。 我得到了这个,但我的应用程序没有使用任何钩子,也没有 react 或 react-dom 重复项。 我正在使用 next.js。 这可能与它有关吗?

npm ls react
npm ls react-dom

@maapteh是给我的吗? 我确实运行了这些命令,但没有发现任何重复项。 两个库的版本均为 16.13.1

@dancancro我也在使用 Next.js,无法解决这个问题。

npm ls reactnpm ls react-dom都只返回一个条目。 但我不确定这是否正确。 链接到本地​​包进行开发时遇到此错误。 npm ls即使我没有将依赖项中的 react 链接回主存储库,也只返回一个条目。 但即使我确实链接反应正确,我仍然得到错误。

@justincy我的项目中没有任何包链接。 我打赌它与 Next.js 有关。 如果我将主要组件放在typeof document !== 'undefined'中,问题就消失了,这实际上破坏了 Next.js 的目的

我设法通过从依赖项中的 node_modules 中删除 react 和 react-dom 来解决我的问题。 这并不理想,但至少我可以继续工作。

@dancancro我怀疑您的问题是由 Next.js 引起的。 如果是这样,很多其他人都会遇到问题。 我只是因为链接包而遇到它。 如果没有链接包,我看不到错误。

如果我删除主要组件中七个组件中的五个,问题就会消失。 我看不出这些组件有什么特别之处。 将这些组件包装在typeof document !== 'undefined'中也可以。

嗨团队,我正在尝试将 React 版本从 16.2.0 升级到 16.13.1,对 react-dom 也做了同样的事情。
现在我有一个在“/test”处调用的包装器组件

class TestWrapper extends React.Component { render() { return ( <React.Fragment> <TestComponent /> </React.Fragment> ) } }

在测试包装器中,我导入了一个带有钩子的功能组件
function TestComponent(props) { useEffect(() => { console.log("TEST COMPONENT"); }); return ( <div> Hello world! </div> ) }

但是当页面呈现 UseEffect 钩子不起作用并发生错误时,即 Invalid Hook Call Warning
PS。 :

  1. 我已经检查过我只有一份 react 并且安装了 react-dom
  2. React 和 react-dom 版本是 16.13.1

这就是我所拥有的
我只是 ...
@@
ReactError
我使用 nextJS 所以它不需要 React 导入。 我试过了——没用。

所有其他页面和功能都运行良好

@Brotipok什么版本的 next.js? (看到类似的问题,但仅在从 9.4.X 迁移到 9.5 时)

你好!

我犯了同样的错误,当我做 npm ls 时,只有一个用于 react 和 react dom 的包。

反应版本:16.13.1
反应 dom 版本:16.13.1

我正在使用打字稿,我已经用 create-react-app my-app --template typescript 初始化了项目。

仅当我没有在其中使用钩子时,功能组件才有效。

包.json

{
“名称”:“blablamovie”,
“版本”:“0.1.0”,
“私人”:真的,
“依赖”:{
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^24.9.1",
"@types/node": "^12.12.53",
"@types/react": "^16.9.43",
"@types/react-dom": "^16.9.8",
"@types/react-router-dom": "^5.1.5",
“反应图标”:“^3.10.0”,
“反应脚本”:“3.4.1”,
“打字稿”:“^3.7.5”,
“webpack-bundle-analyzer”:“^3.8.0”
},
“脚本”:{
“开始”:“反应脚本开始”,
"build": "react-scripts build",
"test": "react-scripts 测试",
"eject": "react-scripts 弹出",
“分析”:“source-map-explorer 'build/static/js/*.js'”
},
“eslintConfig”:{
“扩展”:“反应应用程序”
},
“浏览器列表”:{
“生产”: [
">0.2%",
“没死”,
“不是所有的 op_mini”
],
“发展”: [
“最后 1 个 chrome 版本”,
“最后 1 个 Firefox 版本”,
“最后 1 个 Safari 版本”
]
}
}
我是一个重要的项目,它让我有点疯狂。
如果有人可以提供帮助,那就太好了。
谢谢。

@Brotipok什么版本的 next.js? (看到类似的问题,但仅在从 9.4.X 迁移到 9.5 时)

这是依赖项
“依赖”:{
“下一个”:“9.4.4”,
"下一个图像": "^1.4.0",
“节点萨斯”:“^4.14.1”,
“反应”:“16.13.1”,
“反应文档元”:“^3.0.0-beta.2”,
“反应域”:“16.13.1”,
“反应水平时间线”:“^1.5.3”,
“反应元标签”:“^0.7.4”,
"react-onclickoutside": "^6.9.0"
},
“开发依赖”:{
"@types/node": "^14.0.23",
"@types/react": "^16.9.43",
“打字稿”:“^3.9.7”
}

我在导入material-ui/core/Dialog组件时遇到了同样的问题,我已将我的package.json设置为专门针对reactreact-dom使用 react 16.8.0 react-dom进口。

我只用一次导入运行了npm ls reactnpm ls react-dom我还尝试了错误页面中描述的测试:

// Add this in node_modules/react-dom/index.js
window.React1 = require('react');

// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);

返回false ,但是我将如何追踪依赖项导入的“不同”反应版本?,它似乎只在我导入Material UI Dialog组件时发生,只要点击它就会发生触发它进行渲染的按钮。 我可以使用其他组件,例如ListListItems等。

我尝试强制解决,但也没有解决。

我没有使用 web pack(非常小的项目),所以如果有影响的话,构建会使用react-scripts build

重写:我将用解决方案参考替换我的问题(对于我们这些傻瓜,我可能会要求文档中的术语更加清晰?:))

背景:
我试图将带有钩子的功能组件 webpack-compile 到一个可以从浏览器中的 vanilla JS 调用该组件的资产中。

例如,

function Example() {
    const [count, setCount] = React.useState(0);

    return <button onClick={() => setCount(count + 1)}>
        You clicked {count} times
    </button>;
}
export default Example;

...我想将其作为模块本身导出,并在加载该资产后,直接从 HTML 中使用它,类似于:

<script defer>
            ReactDOM.render(
                ExportedCompiledExample.default(props),
                document.getElementById("my_element")
            );
</script>

我很久以前就开始工作了_只要组件不包含钩子_。 但是当使用钩子时,我一直遇到这个可怕的错误消息。

翻转表格的简单解决方案
我遵循了_很多_更复杂的红鲱鱼(多个 react/reactDOM 版本/实例、npm 导入和隐藏的辅助依赖项、react-hot-loader、webpack 设置、外部、不同的包/模块/库约定、编译后结构.. .) 在尝试这个之前,它有效:

export default () => <Example />;

(或export default props => <Example {...props} /> ,如适用)。

我想,回顾 20/20 是有道理的。

但只是为了查明混乱的根源,以防其他人需要它:钩子规则文档说_在函数组件主体的顶层调用它们_。 我以为我做到了,因为我实际上将示例直接粘贴到我的结构中。

我的解释是,从例子中...

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

...本身不是功能组件吗? 它在正确的调用上下文中变得如此(所以,不是Example()而是<Example /> )。

我想我可能在文档的其他地方错过了它,但万一没有:如果包含/提到/链接到一些使用上下文(或只是 ES 模块设置),它会为我节省很多时间。 :) 特别是因为直接export default Example版本没有钩子。

感谢@apieceofbart 提供有效的解决方案! 我的问题与 npm 链接有关。

这是我使用 Create React App 的方法,其中 Webpack 配置被设计隐藏。 @florianzemma 也可能是您的解决方案?

  1. npm install -D react-app-rewired
  2. 在您的项目根目录中创建一个名为config-overrides.js的文件。
// config-overrides.js
module.exports = function override(config, env) {
  const path = require('path');

  return {
    ...config,
    resolve: {
      ...config.resolve,
      alias: {
        ...config.resolve.alias,
        react: path.resolve('./node_modules/react')
      }
    }
  };
}
  1. 将 package.json 中相关的react-scripts ... -commands 替换为react-app-rewired ...

我希望它有帮助

我收到此错误是因为我加载了 2 次捆绑包。
在我的情况下,它发生是因为渲染脚本标签的 nunjucks 模板已被使用了 2 次 - 在布局本身中,以及在头部标签内容的一般模板中,

纱线解决方法

我正在使用 Yarn,并通过在我的package.json强制解析来解决此问题:

  "resolutions": {
    "**/react": "16.7.0-alpha.2",
    "**/react-dom": "16.7.0-alpha.2"
  },

除了在父应用程序(消费库)中添加分辨率之外,我还使用以下命令更新了库依赖项:

  1. yarn add link:/path/to/parent-app/node_modules/react
  2. yarn add link:/path/to/parent-app/node_modules/react-dom

在此之后,我用yarn add link:/path/to/library重新链接了父应用程序中的库

你好
我在纱线工作区遇到了同样的问题。
我有这样的布局:

工作区/
├── 图书馆/
├── app1/
├── app2/

app1 和 app2 直接依赖于 react v16.9.0、react-dom v16.9.0 和“库”。
'library' 具有对 v16.9.0 反应的对等依赖性,但也对故事书具有开发依赖性。
问题似乎来自依赖于 react v16.13.1 的故事书。
但是,当我运行 yarn install 时,我最终会在我的顶级 node_modules 中使用 react 16.13.1,并在 app1 和 app2 的本地 node_modules 中使用 react 16.9.0。

当我运行 app1(使用 CRA 创建)时,它使用的是本地 react v16.9.0,但“库”中的组件使用的是 React v16.13.1

在我看来,这似乎是纱线提升逻辑、create-react-apps 的 webpack 定义或两者兼而有之的问题?
有人知道这种情况的解决方法吗?

你好
我在纱线工作区遇到了同样的问题。
我有这样的布局:

工作区/
├── 图书馆/
├── app1/
├── app2/

app1 和 app2 直接依赖于 react v16.9.0、react-dom v16.9.0 和“库”。
'library' 具有对 v16.9.0 反应的对等依赖性,但也对故事书具有开发依赖性。
问题似乎来自依赖于 react v16.13.1 的故事书。
但是,当我运行 yarn install 时,我最终会在我的顶级 node_modules 中使用 react 16.13.1,并在 app1 和 app2 的本地 node_modules 中使用 react 16.9.0。

当我运行 app1(使用 CRA 创建)时,它使用的是本地 react v16.9.0,但“库”中的组件使用的是 React v16.13.1

在我看来,这似乎是纱线提升逻辑、create-react-apps 的 webpack 定义或两者兼而有之的问题?
有人知道这种情况的解决方法吗?

我为此找到的唯一解决方案是yarn run eject CRA 应用程序并将resolve部分的顺序从:

```javascript
模块:['node_modules',paths.appNodeModules].concat(
modules.additionalModulePaths || []
),
````


```javascript
模块:[paths.appNodeModules, 'node_modules'].concat(
modules.additionalModulePaths || []
),
````

对我来说,“appNodeModules”不是最高优先级似乎很奇怪——在解决依赖关系时,确实应该推迟到有问题的实际应用程序?

我在涉及 Webpack 和 Electron 的设置中遇到了“钩子”问题。 我的项目依赖于一个模块 A,该模块 A 本身由 Webpack 捆绑(并且是我自己编写的)。 我从 A 外部化了 React(声明它是一个 commonjs2 模块)。 这会从库包中排除 React 文件。

我在 Electron Renderer 进程中运行的主程序也使用 React。 我让 Webpack 将 React 包含在包中(没有特殊配置)。

然而,由于运行时环境中有两个 React 实例,这产生了“钩子”问题。

这是由以下事实造成的:

  • 模块 A '需要' React,这由 Electron 的模块系统解决。 所以 Electron 从 node_modules 中获取 React;
  • 主程序依赖于 Webpack 运行时从包本身“加载”React。
  • Electron 和 Webpack 运行时都有自己的模块缓存......

我的解决方案也是将 React 从主程序中外部化。 这样,主程序和模块 A 都从 Electron 获取它们的 React - 内存中的单个实例。

我尝试了任意数量的别名,但这并不能解决问题,因为别名仅指示 Webpack 在哪里可以找到模块代码。 对于多模块缓存的问题,它没有任何作用!

如果您在无法控制的模块中遇到此问题,请了解 React 是否以及如何外部化。 如果它没有外化,我认为你无法在 Electron 的上下文中解决这个问题。 如果它只是外部化为全局,请将 React 放入您的 .html 文件中,并使您的主程序也依赖它。

最后...

//webpack.config.js

module.exports = {
  ...
  externals: {
      react: 'react',
  },
}

Vue3也有同样的问题

我解决了这个问题,将reactreact-dom作为peerDependencies放在使用 React 的外部库的 package.json 中。

  "peerDependencies": {
    "react": "^16.13.1",
    "react-dom": "^16.13.1"
  },

我想我可能在文档的其他地方错过了它,但万一没有:如果包含/提到/链接到一些使用上下文(或只是 ES 模块设置),它会为我节省很多时间。 :) 特别是因为直接export default Example版本没有钩子。

@espen42
我真的希望你的解决方案能帮助我们。 就像你提到的那样,我们真的尝试了_一切_。

不幸的是,您的解决方案似乎也无济于事。 我想知道也许我错过了什么?

所以,在一个包中(我称之为@bla/bla),我们有index.js有一个带有钩子的组件,比如

function Bla = ({...props]) => {
const [bla, setBla] = useState(false);
return bla ? <div {...props} /> : 'no luck';
}

我们使用npx babel编译包。

我们将此包与npm link链接,然后将其包含在项目中,如npm link @bla/bla
包和项目都使用相同版本的 React 和 react-dom。

在项目中,我们包含这样的包:

import Bla from `@bla/bla`

const RenderBla = ({...props}) => <Bla {...props} />

export default RenderBla

不幸的是,错误仍然存​​在。
Invalid hook call. Hooks can only be called inside of the body of a function component.

我们可以缺少什么?

"externals": {
  "react": "react",
  "react-dom": "react-dom"
}

这个解决了我的问题,非常感谢你❤️

通过外部链接访问时字段定制器错误 (Sharepoint Online)

带有一些结构 UI 组件的 spfx 字段定制器扩展,当通过链接访问时,根据结构 UI 版本获得以下错误之一:
https://reactjs.org/docs/error-decoder.html/?invariant=321 ,
https://reactjs.org/docs/error-decoder.html/?invariant=290&args []=A.%20General

刷新页面后,一切正常。
我没有在代码中使用任何 React Hooks,只有 React Components。
也没有使用任何参考。

我认为这可能是由于 Fabric ui 导致的,当所有 Fabric ui 组件被删除时,没有发生错误。

尝试了不同版本的fabic ui,6.189.2、6.214.0和7.114.1,还尝试用fluent ui替换所有fabric-ui引用,问题仍然存在

检查反应版本,这是输出
npm ls 反应
+-- @microsoft/ [email protected]
| +-- @microsoft/office-ui-fabric-react-bundle@ 1.9.1
| | -- [email protected] deduped | +-- @microsoft/[email protected] | | -- [email protected]去重
| +-- @microsoft/ [email protected]
| | -- [email protected] deduped | -- [email protected]去重
`--反应@16.8.5

大家好,
我也偶然发现了这个恼人的错误。 就我而言,这最终也是我的 webpack 构建的错误配置。 但是这个问题中的建议都没有对我有用。 所以我也想分享一下我的经验。

我的页面包含多个入口点,SplitChunkPlugin 可以创建运行时块。 因为我们使用的是 rails-webpacker gem,所以它默认配置为为每个块创建一个运行时。 但是 webpack 默认做类似的事情,它在块中包含运行时。

当然,文档会警告这种情况,但你必须找到它。 将optimization.runtimeChunk设置为single将创建一个单独的运行时。 当从多个入口点使用 react 时,这将防止您的构建实例化多个 react 副本。

请参阅https://webpack.js.org/configuration/optimization/#optimizationruntimechunk

嘿大家,
我有一个问题,我想使用来自 CDN 并包含在<script>标记中的外部库,因此我对代码本身无能为力。 该库使用反应和钩子,所以我得到了
3. You might have more than one copy of React in the same app错误。
遗憾的是,该库没有 NPM 包: https ://github.com/Anyline/anyline-ocr-anylinejs-module
我正在使用 CRA 并且该项目没有被弹出。

创建了一个小示例Sandbox

它抛出了同样的错误,因为另一个包也使用了钩子,但有自己的 React。 我必须将我的包发布到 NPM,然后直接从 NPM 导入。 那

我最近遇到这个问题,想知道为什么。
我通过将它上传到 GitLab 并通过地址安装它来解决它。
包和本地包有什么区别?

我发现我收到“无效的挂钩调用”。 当我动态加载调用钩子的组件时。

代码沙箱

静态加载“App”的测试通过。 动态加载它的两个测试(一个使用require ,一个使用import作为函数)都给出了错误。

为什么我什至关心:我正在尝试编写一些测试,其中我使用 jest.doMock 来模拟一些东西,然后根据文档动态加载我想要测试的模块。 我使用 doMock 而不是 Mock 因为我需要能够在不同的函数中以不同的方式模拟事物。 但是,您会注意到错误发生时没有涉及任何模拟。

它抛出了同样的错误,因为另一个包也使用了钩子,但有自己的 React。 我必须将我的包发布到 NPM,然后直接从 NPM 导入。 那

我最近遇到这个问题,想知道为什么。
我通过将它上传到 GitLab 并通过地址安装它来解决它。
包和本地包有什么区别?

@catsheue对你来说是React1 === React2 true吗?
我还没有在 npm 上发表我的但想知道这是否是原因

我的似乎是React1 === React2 = true并没有找到解决方案,为什么当我将我的反应库导入项目时会发生这种情况

使用yarn link测试本地库时遇到了同样的问题。 我的错误是将reactreact-dom列为开发依赖项而不是对等项。

所以我应该做yarn add --peer react react-dom最后,因为我已经犯了将 React 作为开发依赖项提交的错误,所以我需要从我的库中清除 node_modules。 rm -rf node_modules; yarn为我解决了这个问题。

我也遇到过这个问题。 就我而言,这是由 Storybook (v6.0.28) 中的重复 React 引起的。 我相信你可以在这里找到更多信息。

我卸载了 Storybook 依赖项,删除node_modules并再次运行yarn install 。 这对我有用。 我希望它可以帮助某人避免为此流泪和浪费时间。

这种解决方法也适用于我。 我正在使用 Firebase 函数,并且在我的项目根目录和/functions/目录下都有一个node_modules文件夹。 如果我删除/functions/node_modules ,我的应用程序运行良好。 这是一种解决方法,但它相当烦人。 有没有人找到允许两个node_modules文件夹同时存在的解决方法?

对于后代以及在使用create-react-app创建的应用程序中使用 mdbootstrap 时可能遇到此问题的任何人。

我在添加各种 mdbootstrap 组件(例如按钮和卡片图像)时看到了这个错误。 根据 React 支持文章添加到 index.js 以进行故障排除的控制台输出在比较版本时返回true 。 所以我不得不尝试别的东西。

解决方法是运行npm dedupe

npm ls react

+-- [email protected]
| `-- [email protected]
`-- [email protected]

npm dedupe

npm ls react

+-- [email protected]
| `-- [email protected]  deduped
`-- [email protected]

在此之后,所有组件都工作得很好。 快乐的时光。

我发现我收到“无效的挂钩调用”。 当我动态加载调用钩子的组件时。

代码沙箱

静态加载“App”的测试通过。 动态加载它的两个测试(一个使用require ,一个使用import作为函数)都给出了错误。

为什么我什至关心:我正在尝试编写一些测试,其中我使用 jest.doMock 来模拟一些东西,然后根据文档动态加载我想要测试的模块。 我使用 doMock 而不是 Mock 因为我需要能够在不同的函数中以不同的方式模拟事物。 但是,您会注意到错误发生时没有涉及任何模拟。

@miket01正是我尝试做的(但没有嘲笑)。 您找到任何解决方案了吗?

遇到这种情况:

function HeadedSection (props) {
   if (!ReactDOMServer.renderToStaticMarkup(props.children))
        return null;

    const [hidden, set_hidden] = useState(props.hidden);

通过先调用useState修复:

function HeadedSection (props) {
    const [hidden, set_hidden] = useState(props.hidden);

    if (!ReactDOMServer.renderToStaticMarkup(props.children))
        return null;

将其搁置数月后,我仍然收到此错误。

我在我的程序中使用零挂钩。 正好有一份react和一份react-dom的副本,它们是相同的版本。 没有链接。

在我最近尝试更新一些软件包以解决安全问题之前,它已经部分起作用了。 我正在使用 next.js,修复方法是通过将一些子组件包装在{typeof window !== 'undefined'中来从顶级组件中排除它们,但现在这也不起作用。

[18:50:42] (master) questions
// ♥ npm ls react
[email protected] /Users/Dan/work/b/questions
└── [email protected]

[22:46:34] (master) questions
// ♥ npm ls react-dom
[email protected] /Users/Dan/work/b/questions
└── [email protected]

[22:46:55] (master) questions
// ♥ npm dedupe
removed 55 packages, moved 46 packages and audited 1712 packages in 65.449s

33 packages are looking for funding
  run `npm fund` for details

found 26 vulnerabilities (15 low, 3 moderate, 8 high)
  run `npm audit fix` to fix them, or `npm audit` for details

抛出错误是因为ReactCurrentDispatcher.current === null但我在/node_modules/react/cjs/react.development.js中找不到任何设置为某物的地方。

有人能告诉我ReactCurrentDispatcher.current应该在哪里获得价值吗?
https://github.com/facebook/react/search?p=2&q=%22ReactCurrentDispatcher.current+%3D%22&type=code

这看起来像一个候选人,但这个代码不包含在我的react-development.js中。 应该是吗?

    const prevPartialRenderer = currentPartialRenderer;
    setCurrentPartialRenderer(this);
    const prevDispatcher = ReactCurrentDispatcher.current;
    ReactCurrentDispatcher.current = Dispatcher;

https://github.com/facebook/react/blob/702fad4b1b48ac8f626ed3f35e8f86f5ea728084/packages/react-dom/src/server/ReactPartialRenderer.js#L859

我在next.js的服务器端渲染中收到此错误,此代码位于react-dom/server下的反应源中。 如何确定/node_modules/react/cjs/react-development.js是否正确?

更新:这是问题所在。 我在next.config.js文件中编辑webpack.config.externals
https://github.com/vercel/next.js/issues/17592#issuecomment -712443172

每当我尝试将材料 UI 集成到其中时,我的应用程序都会引发大量错误(无效的挂钩调用)。 我对 React 完全陌生,所以我需要帮助。

此页面是否有帮助?
0 / 5 - 0 等级