javascript - 从自定义 React 组件库导入和使用组件会导致 Invariant Violation: Invalid hook call
问题描述
我的工作是制作一个 React UI 工具包/组件库,供我们的产品内部使用。在 Storybook 上开发和展示时一切正常。
在从 create-react-app 开箱即用的通用项目中测试库时,导入和实现不使用 React Hooks 制作的组件是可以的,但是一旦我们使用使用 Hooks 制作的组件 - 无效的 Hook Call 错误显示:https ://reactjs.org/warnings/invalid-hook-call-warning.html
已经尝试了那里列出的所有内容(并阅读并尝试了页面上链接的 github 线程解决方案),并且只使用了该组件useRef()
而没有其他任何东西,所以我们知道没有违反任何规则,React 和 React-dom 版本是最新的,并且正在npm ls react
运行npm ls react-dom
在项目结果中react@16.10.2
,react-dom@16.10.2
没有别的......所以看起来我们没有多个 React 的?
任何帮助将非常感激!!
这是 UI 套件的package.json
{
"name": "react-ui-kit",
"version": "0.0.15",
"description": "UI Kit",
"main": "dist/index",
"module": "dist/index",
"typings": "dist/index",
"jest": {
"setupFilesAfterEnv": [
"<rootDir>/setupTests.js"
],
"coverageReporters": [
"json-summary",
"text",
"lcov"
]
},
"scripts": {
"test": "jest --coverage",
"test:badges": "npm run test && jest-coverage-badges input './coverage/coverage-summary.json' output './badges'",
"test-update": "jest --updateSnapshot",
"lint:css": "stylelint './src/**/*.js'",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook -c .storybook -o .out",
"generate": "plop --plopfile ./.plop/plop.config.js",
"build": "webpack --mode production",
"prepare": "npm run build",
"prepublishOnly": "npm run test:badges",
"storybook-docs": "build-storybook --docs",
"todo": "leasot './src/**/*.js'",
"todo-ci": "leasot -x --reporter markdown './src/**/*.js' > TODO.md"
},
"license": "ISC",
"peerDependencies": {
"prop-types": "^15.7.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"recharts": "^1.7.1",
"styled-components": "^4.3.2",
"styled-normalize": "^8.0.6"
},
"devDependencies": {
"@babel/cli": "^7.6.0",
"@babel/core": "^7.6.0",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.6.0",
"@babel/preset-react": "^7.0.0",
"@storybook/addon-actions": "^5.2.1",
"@storybook/addon-docs": "^5.2.1",
"@storybook/addon-info": "^5.2.1",
"@storybook/addon-knobs": "^5.2.1",
"@storybook/addon-links": "^5.2.1",
"@storybook/addon-viewport": "^5.2.1",
"@storybook/addons": "^5.2.1",
"@storybook/react": "^5.2.1",
"babel-eslint": "^10.0.3",
"babel-jest": "^24.9.0",
"babel-loader": "^8.0.6",
"babel-plugin-styled-components": "^1.10.6",
"eslint": "^6.5.1",
"eslint-plugin-react": "^7.15.0",
"eslint-plugin-react-hooks": "^2.1.1",
"jest": "^24.9.0",
"jest-coverage-badges": "^1.1.2",
"jest-styled-components": "^6.3.3",
"leasot": "^8.2.0",
"plop": "^2.4.0",
"polished": "^3.4.1",
"prop-types": "^15.7.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-test-renderer": "^16.9.0",
"recharts": "^1.7.1",
"storybook-styled-components": "github:merishas/storybook-styled-components",
"styled-components": "^4.4.0",
"styled-normalize": "^8.0.6",
"stylelint": "^10.1.0",
"stylelint-config-recommended": "^2.2.0",
"stylelint-config-styled-components": "^0.1.1",
"stylelint-processor-styled-components": "^1.8.0",
"webpack": "^4.40.2",
"webpack-cli": "^3.3.9"
},
"files": [
"dist"
],
}
UI 套件的webpack.config.js
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve('dist'),
filename: 'index.js',
libraryTarget: 'commonjs2',
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
use: 'babel-loader',
},
{
test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
limit: 10000,
mimetype: 'application/font-woff',
},
},
],
},
],
},
resolve: {
alias: {
components: path.resolve(__dirname, 'src/components/'),
utils: path.resolve(__dirname, 'src/utils/'),
themes: path.resolve(__dirname, 'src/themes/'),
},
extensions: ['.js', '.jsx'],
},
devtool: false,
};
在项目中如何导入和实现组件:
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import { FieldLabel, Button } from "react-ui-kit";
function App() {
return (
<div className="App">
<FieldLabel>THIS IS THE ONE USING the useRef Hook</FieldLabel>
<Button>This component is totally fine without FieldLabel, this isn't using Hooks</Button>
</div>
);
}
export default App;
解决方案
查看 webpack 配置,我可以看到,UI 工具包被捆绑在一起,react
这可能会导致问题。
为避免这种情况,您可以使用 webpack externals。
https://webpack.js.org/configuration/externals/
externals 配置选项提供了一种从输出包中排除依赖项的方法。相反,创建的包依赖于存在于消费者环境中的依赖项。此功能通常对库开发人员最有用,但它有多种应用程序。
因此,您可以将 UI Kit webpack 配置更新为不包含react
,并且 peerDependencies 应该负责处理库的任何使用者的依赖关系。
更新了 webpack.config
const path = require("path");
module.exports = {
mode: "production",
entry: "./src/index.js",
output: {
path: path.resolve("dist"),
filename: "index.js",
libraryTarget: "commonjs2"
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
use: "babel-loader"
},
{
test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[ext]",
limit: 10000,
mimetype: "application/font-woff"
}
}
]
}
]
},
resolve: {
alias: {
components: path.resolve(__dirname, "src/components/"),
utils: path.resolve(__dirname, "src/utils/"),
themes: path.resolve(__dirname, "src/themes/")
},
extensions: [".js", ".jsx"]
},
externals: {
// Use external version of React
react: "react"
},
devtool: false
};
我已经发布了一个测试包来确认这一点(react-ui-kit-dontuse)。
演示链接
v0.0.21(Without webpack externals)
https://stackblitz.com/edit/react-xyjgep
v0.0.23(With webpack externals)
https://stackblitz.com/edit/react-ihnmrl
测试包源码:https ://github.com/nithinthampi/react-ui-lib-test
希望这可以帮助!
推荐阅读
- postgresql - 如何将 Docker-Compose Postgres 的卷迁移到另一台主机?
- android - 为什么隐式意图有时会启动不正确的活动/意图?
- azure - Azure SQL LTR 备份 - 防止逻辑服务器删除
- vb.net - .Net DirectorySearcher 未检索用户对象中的所有值
- json - 在sql select语句中传递json值
- php - Solr:对具有空格的术语使用通配符
- google-colaboratory - google colab 中的 drive.mount('/content/drive') 超时
- vue.js - 将 vue 数据发送回服务器
- mongodb - Azure CosmosDB 能否存储非 ASCII 字符以支持多语言数据存储?
- swift - AudioPlayer (Swift) - 两次播放声音 - 有间隙