千家信息网

如何解决第三方组件的Hooks报错问题

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要介绍"如何解决第三方组件的Hooks报错问题",在日常操作中,相信很多人在如何解决第三方组件的Hooks报错问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答
千家信息网最后更新 2026年11月02日如何解决第三方组件的Hooks报错问题

这篇文章主要介绍"如何解决第三方组件的Hooks报错问题",在日常操作中,相信很多人在如何解决第三方组件的Hooks报错问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何解决第三方组件的Hooks报错问题"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

事发

某个需求需要引入一个第三方组件库。

当引入组件库中的函数组件A后,React运行时报错:

  • "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons...

从React文档了解到,这是由于「错误使用Hooks造成的」。

官网给出的可能的错误原因有3种:

1.React和ReactDOM版本不匹配

需要v16.8以上版本的ReactDOM才支持Hooks。

我们项目使用的是v17.0.2,不属于这个原因。

2.打破了Hooks的规则

Hooks只能在函数组件或自定义Hooks顶层调用。

翻看A组件源码,报错的是一个顶层调用的useRef:

function A() {   // ...   var xxxRef = useRef(null);   // ... }

不属于这个原因。

3.重复的React

载录自React文档:

  • 为了使 Hook 正常工作,你应用代码中的 react 依赖以及 react-dom 的 package 内部使用的 react 依赖,必须解析为同一个模块。

  • 如果这些 react 依赖解析为两个不同的导出对象,你就会看到本警告。这可能发生在你意外地引入了两个 react 的 package 副本。

读起来好绕,看起来这条的嫌疑最大。

定位问题

在报错的useRef中打上断点,发现其来自于:

http://localhost:8081/Users/项目目录/node_modules/组件库/node_modules/react/cjs/react.development.js

在项目里其他调用Hooks但是未报错的地方打上断点,发现资源来自于:

http://localhost:8081/Users/项目目录/node_modules/react/cjs/react.development.js

报错的useRef和项目其他Hooks引用了不同的react.development.js。

翻看「组件库」的package.json,发现他将react与react-dom作为dependencies安装:

"dependencies": {   "react": "^16.13.1",   "@babel/runtime-corejs3": "^7.11.2",   "react-dom": "^16.13.1" },

这样会在「组件库」目录的node_modules下创建这两个依赖。

作为一个「组件库」,这么做显然是不合适的。

临时解决

最好的做法是将这两个依赖作为peerDependencies,即将其作为外部依赖。

这样,当我们引入「组件库」时,「组件库」会使用我们项目中的react与react-dom,而不是自己安装一份。

但是我没有这个「组件库」的权限,只能在自己项目中做文章。

在package.json文档中提供了一个配置项:resolutions,可以临时解决这个问题。

resolutions允许你复写一个在项目node_modules中被嵌套引用的包的版本。

在我们项目的package.json中作出如下修改:

// 项目package.json {   // ...   "resolutions": {     "react": "17.0.2",     "react-dom": "17.0.2"   },   // ... }

这样,项目中用到的这两个依赖都会使用resolutions中指定的版本。

不管是「组件库」还是我们的项目代码中的react与react-dom,都会指向同一个文件。

现在问题是临时解决了,但是造成问题的原因是什么?

让我们深入Hooks源码内部来寻找答案。

深入源码

首先让我们思考2个问题:

当我们在一个Hooks内部调用其他Hooks时会报开篇提到的错误。

比如如下代码就会报错:

function App() {    useEffect(() => {     const a = useRef();   }, [])    // ... }

Hooks只是函数,他如何感知到自己在另一个Hooks内部执行?

就如上例子,useRef如何感知到自己在useEffect的回调函数中执行?

再看另一个问题,我们知道classComponent有componentDidMount与componentDidUpdate两个生命周期函数区分mount时与update时。

那么Hooks作为函数,怎么区分当前是mount时还是update时?

显然,Hooks源码内部存在一种机制,能够感知当前执行的上下文环境。

渐入佳境

在浏览器环境,我们会引用react与reactDOM两个包。

其中,在react包的代码中存在一个变量ReactCurrentDispatcher。

他的current参数指向当前正在使用的Hooks上下文:

var ReactCurrentDispatcher = {   /**    * @internal    * @type {ReactComponent}    */   current: null };

同时,在reactDOM中,在程序运行过程中,ReactCurrentDispatcher.current会根据当前上下文环境指向不同引用。

比如:

var HooksDispatcherOnMountInDEV = {   useState: function() { // ... },   useEffect: function() { // ... },   useRef: function() { // ... },   // ... } var HooksDispatcherOnUpdateInDEV = {   useState: function() { // ... },   useEffect: function() { // ... },   useRef: function() { // ... },   // ... } // ...

当处在DEV环境mount时,ReactCurrentDispatcher.current会指向HooksDispatcherOnMountInDEV。

当处在DEV环境update时,ReactCurrentDispatcher.current会指向HooksDispatcherOnUpdateInDEV。

再来看useRef的定义:

function useRef(initialValue) {   var dispatcher = resolveDispatcher();   return dispatcher.useRef(initialValue); }

内部调用的是dispatcher.useRef。

dispatcher即ReactCurrentDispatcher.current。

function resolveDispatcher() {   var dispatcher = ReactCurrentDispatcher.current;    if (!(dispatcher !== null)) {     {       throw Error( "Invalid hook call. ..." );     }   }    return dispatcher; }
  • 可以看到,开篇的错误正是由于dispatcher为null时抛出

这就是Hooks能区分mount与update的原因。

同理,DEV环境,当一个Hooks在执行时,ReactCurrentDispatcher.current会指向引用 —— InvalidNestedHooksDispatcherOnUpdateInDEV。

在这种情况下再调用的Hooks,比如如下useRef:

var InvalidNestedHooksDispatcherOnUpdateInDEV = {   // ...   useRef: function (initialValue) {     currentHookNameInDev = 'useRef';     warnInvalidHookAccess();     updateHookTypesDev();     return updateRef();   },   // ... }

内部都会执行warnInvalidHookAccess报错,提示自己在别的Hooks内执行了。

真相大白

到这里我们终于知道开篇提到的问题发生的本质原因:

  • 由于「组件库」使用dependencies而不是peerDependencies,导致「组件库」中引用的react与reactDOM是「组件库」目录node_modules下的文件。

  • 项目中使用的react与reactDOM是项目目录node_modules下的文件。

  • 「组件库」中react与项目目录中react在运行时分别初始化ReactCurrentDispatcher

  • 这两个ReactCurrentDispatcher分别依赖对应目录的reactDOM

  • 我们在项目中执行项目目录下reactDOM的ReactDOM.render方法,他会随着程序运行改变项目目录中react包下的ReactCurrentDispatcher.current的指向

  • 「组件库」中的ReactCurrentDispatcher.current始终是null

  • 当调用「组件库」中的Hooks时,由于ReactCurrentDispatcher.current始终是null导致报错

到此,关于"如何解决第三方组件的Hooks报错问题"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

组件 项目 问题 目录 两个 指向 函数 原因 环境 第三方 代码 源码 版本 错误 学习 运行 不同 上下 上下文 开篇 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技网 金融科技还是互联网 天下捷融互联网科技 互联网高科技企业 中正互联网科技招聘 北京三清互联网科技 中盈科技互联网信息有限公司 南平创想时代互联网科技有限公司 阿大互联网科技有限公司 民营互联网公司国防科技 明优互联网科技有限公司 工业互联网展湾科技股份有限公司 广州有谷有贝互联网科技有限公司 2021世界互联网领先科技成果发布 广州梦谷互联网科技有限公司领导 昆明中奇联合互联网科技 普陀区互联网教育科技管理办法 互联网科技机房 三亚科技创新互联网基地 安徽九吞吴互联网科技有限公司 互联网 科技 科技服务与互联网 丰台科技园 互联网公司 甘肃拓世互联网科技有限公司 昭通云南众福互联网科技有限公司 崇明区互联网教育科技售后服务 世界互联网领先科技成果获奖 互联网领先科技宣传片 陕西云淼互联网科技公司 抖集互联网科技技术咨询
0