React + Antd + Rollup 组件库“错误:无效的钩子调用。钩子只能在函数组件体内调用”

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

我目前正在构建一个 UI 库来简化跨多个应用程序的维护。这些目前使用 Ant Design。

一切似乎都很顺利...我在

package.json
rollup.config.js
中添加了我的对等依赖项(通过外部),并且我能够让 Rollup 生成一个 es 和 cjs 二进制文件,该二进制文件成功导出 just 我的代码。

但是,当我将其中任何一个导入我的主机应用程序(Electron 和/或 React,已经使用 antd 没有问题)时,我收到以下错误:

Uncaught Error: 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:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (react.development.js:1476)
    at Object.useContext (react.development.js:1484)
    at Button (button.js:129)
    at renderWithHooks (react-dom.development.js:14985)
    at updateForwardRef (react-dom.development.js:17044)
    at beginWork (react-dom.development.js:19098)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
    at invokeGuardedCallback (react-dom.development.js:4056)
    at beginWork$1 (react-dom.development.js:23964)
resolveDispatcher @ react.development.js:1476
useContext @ react.development.js:1484
Button @ button.js:129
renderWithHooks @ react-dom.development.js:14985
updateForwardRef @ react-dom.development.js:17044
beginWork @ react-dom.development.js:19098
callCallback @ react-dom.development.js:3945
invokeGuardedCallbackDev @ react-dom.development.js:3994
invokeGuardedCallback @ react-dom.development.js:4056
beginWork$1 @ react-dom.development.js:23964
performUnitOfWork @ react-dom.development.js:22779
workLoopSync @ react-dom.development.js:22707
renderRootSync @ react-dom.development.js:22670
performSyncWorkOnRoot @ react-dom.development.js:22293
scheduleUpdateOnFiber @ react-dom.development.js:21881
updateContainer @ react-dom.development.js:25482
(anonymous) @ react-dom.development.js:26021
unbatchedUpdates @ react-dom.development.js:22431
legacyRenderSubtreeIntoContainer @ react-dom.development.js:26020
render @ react-dom.development.js:26103
(anonymous) @ renderer.tsx:129
./src-template/renderer.tsx @ renderer.tsx:150
__webpack_require__ @ bootstrap:789
fn @ bootstrap:100
0 @ renderer.tsx:150
__webpack_require__ @ bootstrap:789
(anonymous) @ bootstrap:856
(anonymous) @ bootstrap:856
react-dom.development.js:20085 The above error occurred in the <Button> component:

    at Button (http://localhost:3000/main_window/index.js:48908:30)
    at ../../ui-library/dist/index.cjs.js.exports.ComponentA (http://localhost:3000/main_window/index.js:101188:13)
    at div
    at App (http://localhost:3000/main_window/index.js:204727:30)

我无法理解如何继续...我尝试调整我的汇总配置(如下)并将所有代码删除为单个测试器组件(antd Button),但我仍然遇到错误。

当我

console.log()
导入对象时,我可以看到 es 和 cjs 二进制文件都公开了测试器组件,但存在错误。

我在这里缺少什么?

同伴依赖

  • 反应
  • 反应 DOM
  • antd
  • @ant-design/图标

Rollup.config.js

import { DEFAULT_EXTENSIONS } from '@babel/core'
import babel from '@rollup/plugin-babel'
import typescript from 'rollup-plugin-typescript2'
import commonjs from '@rollup/plugin-commonjs'
import external from 'rollup-plugin-peer-deps-external'
import postcss from 'rollup-plugin-postcss'
import resolve from '@rollup/plugin-node-resolve'
import url from '@rollup/plugin-url'
import svgr from '@svgr/rollup'
import { terser } from 'rollup-plugin-terser'

import pkg from './package.json'


const isDevelopment = process.env.NODE_ENV === 'development' ? true : false;

console.log('EXPECTED EXTERNALS', [
      ...Object.keys(pkg.dependencies || {}),
      ...Object.keys(pkg.peerDependencies || {})
])
export default {
  input: 'src/index.jsx',
  output: [
    {
      file: `dist/index.es.js`,
      format: 'esm',
      exports: 'named',
      sourcemap: isDevelopment,
    },
    {
      file: `dist/index.cjs.js`,
      format: 'cjs',
      exports: 'named',
      sourcemap: isDevelopment,
    }
  ],
  context: 'this',
  external: [
        ...Object.keys(pkg.dependencies || {}),
        ...Object.keys(pkg.peerDependencies || {})
  ],
  plugins: [
    external(),
    typescript({
      rollupCommonJSResolveHack: true,
      clean: true,
      tsconfig: './tsconfig.json',
    }),
    babel({
      presets: [
        'react-app',
      ],
      extensions: [
        ...DEFAULT_EXTENSIONS,
        '.ts',
        '.tsx',
      ],
      plugins: [
        ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }],
        "@babel/plugin-proposal-object-rest-spread",
        "@babel/plugin-proposal-optional-chaining",
        "@babel/plugin-syntax-dynamic-import",
        "@babel/plugin-proposal-class-properties",
        "transform-react-remove-prop-types"
      ],
      babelHelpers: 'runtime',
    }),
    postcss({
        extensions: ['.css', '.scss', '.less'],
        use: ['sass', ['less', {
          lessOptions: {
             javascriptEnabled: true
          }
        }]],
    }),
    svgr(),
    url(),
    resolve(),
    commonjs(),
    terser({ mangle: true }),
  ],
}

Package.json(组件库)

{
  "name": "ui-library",
  "version": "0.0.1",
  "description": "UI library components",
  "main": "index.js",
  "scripts": {
    "build": "rm -rf dist && mkdir dist && NODE_ENV=production BABEL_ENV=production rollup -c"
  },
  "peerDependencies": {
    "@ant-design/icons": "^4.3.0",
    "antd": "^4.9.2",
    "react": "^17.0.1",
    "react-dom": "^17.0.1"
  },
  "devDependencies": {
    "@babel/core": "^7.12.10",
    "@babel/plugin-proposal-class-properties": "^7.12.1",
    "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
    "@babel/plugin-proposal-optional-chaining": "^7.12.7",
    "@babel/plugin-syntax-dynamic-import": "^7.8.3",
    "@babel/plugin-transform-react-jsx": "^7.12.10",
    "@babel/preset-env": "^7.12.10",
    "@babel/preset-react": "^7.12.10",
    "@babel/preset-typescript": "^7.12.7",
    "@rollup/plugin-babel": "^5.2.2",
    "@rollup/plugin-commonjs": "^17.0.0",
    "@rollup/plugin-node-resolve": "^11.0.0",
    "@rollup/plugin-typescript": "^8.0.0",
    "@rollup/plugin-url": "^6.0.0",
    "@svgr/rollup": "^5.5.0",
    "@types/node": "^14.14.11",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@typescript-eslint/eslint-plugin": "^4.9.1",
    "@typescript-eslint/parser": "^4.9.1",
    "babel-loader": "^8.2.2",
    "babel-plugin-import": "^1.13.3",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "babel-preset-react-app": "^10.0.0",
    "css-loader": "^4.2.1",
    "eslint": "^7.15.0",
    "eslint-config-airbnb-typescript": "^12.0.0",
    "eslint-plugin-react": "^7.21.5",
    "less-loader": "^7.1.0",
    "mini-css-extract-plugin": "^1.3.2",
    "react-is": "^17.0.1",
    "rollup": "^2.34.2",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "rollup-plugin-postcss": "^4.0.0",
    "rollup-plugin-terser": "^7.0.2",
    "rollup-plugin-typescript2": "^0.29.0",
    "sass-loader": "^10.1.0",
    "style-loader": "^2.0.0",
    "typescript": "^4.1.2",
    "url-loader": "^4.1.1"
  }
}

组件库测试器组件

import React from 'react';

import { Button, Radio } from 'antd';
import { DownloadOutlined } from '@ant-design/icons';
import { SizeType } from 'antd/lib/config-provider/SizeContext';


export interface ButtonProps {
  /**
   * What background color to use
   */
  backgroundColor?: string;
  /**
   * Button contents
   */
  label: string;

  /**
   * Size (small | large)
   */
  size: SizeType;
  /**
   * Optional click handler
   */
  onClick?: () => void;
}


// export const ComponentA = (props: ButtonProps) => (<button type="button" onClick={props.onClick} style={{ backgroundColor: props.backgroundColor}}>{ props.label }</button>);

export const ComponentA = (props: ButtonProps) => (
  <Button
    type="primary"
    shape="round"
    icon={<DownloadOutlined />}
    size={props.size || 'middle'}
    onClick={props.onClick || null}
  >
    {props.label || ''}
  </Button>
)

更新:添加了汇总插件可视化器输出

reactjs antd rollupjs
4个回答
25
投票

如果您在主项目中链接库的本地版本以加快开发速度时发生此问题。它可能与“React 的重复版本”有关。

https://reactjs.org/warnings/invalid-hook-call-warning.html

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

简而言之:

  • 在 /your-app/node_modules/react 中运行
    npm link
    。这应该会建立 React 的全局链接。
  • 在 /your-ui-library 中运行
    npm link react
    。这应该使库使用应用程序的 React 副本。

3
投票

尝试将react和react-dom移动到

package.json

中的peerDependencies

指南:https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe#optimizing

"peerDependencies": {
  "react": "^18.1.0",
  "react-dom": "^18.1.0"
}

1
投票

我有同样的问题,使用 rush monorepo,配置 ui-package 并使用 nextjs 构建应用程序。

解决方案是在

package.json

上添加以下代码
"resolutions": {
  "react": "17.0.1", // verificate your react version
  "react-dom": "17.0.1"
}

在此处查看更多信息:https://github.com/vercel/next.js/issues/9022#issuecomment-728688452


0
投票

我在使用 Antd 时遇到了同样的问题。我正在开发最近创建的测试应用程序:

npx create-react-app my_project --模板打字稿

应用程序未弹出。然后我在某个文件中添加了

import {Button} from 'antd'
并开始使用
Button
。奇怪的是,
npm run start
并没有抱怨找不到
antd
库,但是当我尝试运行该应用程序时,我收到了上面显示的“无效的挂钩调用”消息。

跑步:

npm i --S antd

...为我修好了。我仍然没有解释为什么当我最初未能在包依赖项中添加

npm run start
antd
没有抱怨。

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