npm 模块上的无效钩子调用
Posted
技术标签:
【中文标题】npm 模块上的无效钩子调用【英文标题】:Invalid hook call on npm module 【发布时间】:2020-08-28 04:01:52 【问题描述】:首先链接到回购:https://github.com/vmarchesin/react-konami-code
您应该能够构建它(确保取消注释src/index.js
上的导出)并链接到您的项目。也可以使用npm i -S react-konami-code@2.0.0-beta.0
进行尝试并获取钩子的错误。我把 2.0.0-beta.1
的钩子去掉了,因为它坏了。
问题描述
我为我的 npm 模块创建了一个自定义钩子,但在发布或将其用作模块后它不起作用。我怀疑问题在于 webpack 如何捆绑它,但我无法解决它。
采取的步骤
我确保在我的 webpack 配置中将react
和 react-dom
声明为外部变量。
externals: [
react:
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
,
'react-dom':
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom',
,
,
],
在package.json
中将react
和react-dom
声明为peerDependencies
"peerDependencies":
"react": "^16.13.1",
"react-dom": "^16.13.1"
,
挂钩正在工作。如果我声明并使用它,它就可以工作。如果我从模块中导入它(或使用 npm 链接),它不会。这是钩子的代码:
import useEffect, useState, useCallback from 'react';
export default (action,
code = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65],
= ) =>
const [input, setInput] = useState([]);
const onKeyUp = useCallback(
(e) =>
const newInput = input;
newInput.push(e.keyCode);
newInput.splice(-code.length - 1, input.length - code.length);
setInput(newInput);
if (newInput.join('').includes(code.join('')))
action();
,
[input, setInput, code, action],
);
useEffect(() =>
document.addEventListener('keyup', onKeyUp);
return () =>
document.removeEventListener('keyup', onKeyUp);
;
, [onKeyUp]);
;
我没有在类组件中调用钩子。
我正在使用webpack@4.43.0
以及babel@7
和babel-loader@8.1.0
。
这是我为 webpack 构建导出索引文件的方式:
import Konami from './Konami';
export default Konami; // disregard this, it works
export default as useKonami from './useKonami'; // this doesn't work
这是screenshot 和错误记录:
未处理的运行时错误错误:无效的挂钩调用。钩子只能是 在函数组件的主体内部调用。这可能发生 出于以下原因之一:
您可能有不匹配的 React 版本和渲染器(例如 React DOM) 您可能违反了 Hooks 规则 您可能在同一个应用中拥有多个 React 副本
【问题讨论】:
我尝试了github.com/facebook/react/issues/16029 提供的大多数解决方案,但没有任何效果。 你能解决这个问题吗,因为我也遇到了同样的错误。 @Optimus 如果仍然需要,请在下面尝试我的答案。 【参考方案1】:我遇到了同样的问题,尝试了所有解决方案,但都没有奏效。
解决方案是,我们需要将 Webpack 配置为基本上忽略 React 作为生产包的一部分以及对等依赖项。
为此,请在webpack.config.js
中添加以下行:
externals:
"react": "commonjs react",
"react-dom": "commonjs react-dom",
【讨论】:
【参考方案2】:尝试从我构建的 npm 包中导入反应组件时,我遇到了相同的错误消息。正如错误消息的解释所暗示的那样,这可能是duplicate React 的情况。
关于错误消息的重要部分是将react
和react-dom
捆绑为外部导入,以便使用父项目的react,而不是使用第二个,这是一个重复的 React。
我通过使用 rollup.js 构建我的 npm 包解决了这个问题,基本上遵循这个 guide。
我生成的 rollup.config.js:
import pkg from './package.json'
import babel from '@rollup/plugin-babel';
export default
input: 'src/index.js',
output: [
file: pkg.main,
format: 'cjs',
exports: 'named',
sourcemap: true,
strict: false
],
plugins: [babel( babelHelpers: 'bundled' )],
external: ['react', 'react-dom']
您的 npm 包中需要以下开发依赖项(假设您还必须使用 babel 进行转译):
npm i -D rollup babel-core @rollup/plugin-babel
你可以像这样捆绑汇总:
// add that to your package.json
"scripts":
"build": "rollup -c",
"start": "rollup -c -w" // for watching changes
,
使用 npm link
甚至可以在父项目中为您正在开发的打包的 react 组件进行热重载,而无需任何 npm 发布。耶。
【讨论】:
对我来说也是“重复反应”问题。将 react 和 react-native 从 dependencies/devDependencies 移动到我单独的 NPM omponent/package 中的 peerDependencies 中,一切都很好(然后删除所有 node_modules,运行 yarn 等)。【参考方案3】:我在这里看到两个问题,这可能会导致您在控制台上看到的错误:
-
不导入
React
所以破坏了 Rules of Hooks - Only Call Hooks from React Functions。
此外,问题可能来自您这里没有命名组件。
所以我将React
包含在以下内容中:
import React, useEffect, useState, useCallback from 'react';
你也可以尝试如下导出:
export default function ComponentName (action,
code = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65],
= )
// your component code
或者如果你还想使用箭头功能,那么:
const ComponentName = (action,
code = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65],
= ) =>
// your component code
export default ComponentName;
您可以参考这篇文章:Do not use anonymous functions to construct React functional components。
我希望这会有所帮助!
【讨论】:
您好,感谢您的见解。我添加了React
作为导入的一部分,并将匿名箭头函数替换为默认导出的命名函数。清除 node_modules
(模块和测试应用程序)并重新创建 npm link
后,错误仍然存在。
@vmarchesin 如果仍然需要,请尝试我在下面的回答中建议的解决方案。以上是关于npm 模块上的无效钩子调用的主要内容,如果未能解决你的问题,请参考以下文章