【问题标题】:Invalid hook call on npm modulenpm 模块上的无效钩子调用
【发布时间】: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 配置中将 reactreact-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 中将reactreact-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@7babel-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 和错误记录:

未处理的运行时错误错误:无效的挂钩调用。钩子只能是 在函数组件的主体内部调用。这可能发生 出于以下原因之一:

  1. 您可能有不匹配的 React 版本和渲染器(例如 React DOM)
  2. 您可能违反了 Hooks 规则
  3. 您可能在同一个应用中拥有多个 React 副本

【问题讨论】:

  • 我尝试了github.com/facebook/react/issues/16029 提供的大多数解决方案,但没有任何效果。
  • 你能解决这个问题吗,因为我也遇到了同样的错误。
  • @Optimus 如果仍然需要,请在下面尝试我的答案。

标签: reactjs npm webpack react-hooks babeljs


【解决方案1】:

我遇到了同样的问题,尝试了所有解决方案,但都没有奏效。

解决方案是,我们需要将 Webpack 配置为基本上忽略 React 作为生产包的一部分以及对等依赖项。

为此,请在webpack.config.js 中添加以下行:

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

【讨论】:

    【解决方案2】:

    尝试从我构建的 npm 包中导入反应组件时,我遇到了相同的错误消息。正如错误消息的解释所暗示的那样,这可能是duplicate React 的情况。

    关于错误消息的重要部分是将reactreact-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】:

    我在这里看到两个问题,这可能会导致您在控制台上看到的错误:

    1. 不导入 React 所以破坏了 Rules of Hooks - Only Call Hooks from React Functions
    2. 此外,问题可能来自您这里没有命名组件。

    所以我将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 如果仍然需要,请尝试我在下面的回答中建议的解决方案。
    猜你喜欢
    • 2021-01-24
    • 2020-12-02
    • 1970-01-01
    • 2022-01-08
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多