Uncaught Invariant Violation: 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

最近在写一个react组件的时候,遇到了这个问题,因为这个组件是想作为npm包使用,然后在组件里面使用了useEffect,这个组件本身的package.json里安装了react和react-dom作为devDependencies,另外建了测试工程,测试工程里单独装了react和react-dom,用npm link的方式来测试这个组件,然后就遇到这个报错

  1. /** npm 包的组件 package.name = 'demo-a' */
  2. import * as React from 'react'
  3. const title = '12345'
  4. export default function(props) {
  5. console.log('React', React, (React || {}).version || '---')
  6. // 这里返回false,导致出现下面React.useState抛出异常
  7. console.log('React === window.React', React === window.React)
  8. const __react = (window.React || React)
  9. const [title, setTitle] = __react.useState('12345')
  10. return <div>{title}</div>
  11. }
  12. /**
  13. 项目中的react和npm包中的react不是同一个,
  14. console.log('React === window.React', React === window.React)
  15. 返回false
  16. */
  17. import * as React from 'react';
  18. import DemoA from 'demo-a';
  19. export default DemoA;

解决方式

主项目

  1. module.exports = {
  2. ...
  3. resolve: {
  4. // Add `.ts` and `.tsx` as a resolvable extension.
  5. extensions: ['.jsx', '.ts', '.tsx', '.js'],
  6. alias: {
  7. '@': path.resolve(__dirname, '../src'),
  8. // 设置这个
  9. 'react': path.resolve(__dirname, '../node_modules/react'),
  10. 'react-dom': path.resolve(__dirname, '../node_modules/react-dom'),
  11. }
  12. },
  13. ...
  14. }

依赖采用
rollup.config.js
设置例外模块
externals: [‘react’, ‘vue’, ‘react-dom’]
设置打包方式
output.format = es
修改package.js

  1. {
  2. ...
  3. "peerDependencies": {
  4. "react": "^16.7.0",
  5. "react-dom": "^16.7.0"
  6. },
  7. ...
  8. }
  1. // rollup.config.js
  2. const path = require('path');
  3. // const writeCss = require('./config/writeCss');
  4. // 解析 json import json from 'xxx.json'
  5. import json from 'rollup-plugin-json';
  6. // 有时候你会使用npm安装依赖 rollup 不知道如何打破常规去处理这些依赖(node_modules)我们需要添加一些配置。
  7. import resolve from '@rollup/plugin-node-resolve';
  8. import babel from '@rollup/plugin-babel';
  9. import typescript from '@rollup/plugin-typescript';
  10. import less from 'rollup-plugin-less';
  11. import commonjs from '@rollup/plugin-commonjs';
  12. import replace from '@rollup/plugin-replace';
  13. import postcss from 'rollup-plugin-postcss'
  14. import { uglify } from 'rollup-plugin-uglify';
  15. const resolvePath = function(filePath) {
  16. return path.join(__dirname, '.', filePath)
  17. }
  18. console.log(resolvePath('src/index.tsx'))
  19. const ENV = process.env.NODE_ENV;
  20. export default {
  21. sourceMap: true,
  22. input: resolvePath('src/core/index.tsx'),
  23. output: {
  24. file: resolvePath('dist/index.bundle.js'),
  25. // input [a,b,...] 多文件时有问题 umd 格式有问题 [!] Error: UMD and IIFE output formats are not supported for code-splitting builds.
  26. // umd,amd,cjs,iife
  27. format: 'es',
  28. name: 'myLibrary',
  29. sourceMap: true,
  30. },
  31. plugins: [ // 在此处使用插件
  32. resolve({ browser: true, }),
  33. commonjs({
  34. include: [
  35. 'node_modules/**',
  36. 'src/**'
  37. ]
  38. }),
  39. json(),
  40. postcss({ extensions: ['.css', '.sss', '.pcss', '.less'], plugins: [] }),
  41. typescript(),
  42. // https://www.npmjs.com/package/@rollup/plugin-babel
  43. babel({
  44. exclude: 'node_modules/**', // 只编译我们的源代码
  45. extensions: ['.js', '.jsx', '.es6', '.es', '.mjs', '.tsx', '.ts']
  46. }),
  47. replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
  48. ENV === 'production' && uglify()
  49. ],
  50. // 指出应将哪些模块视为外部模块, 外部的(externals),不会与你的库打包在一起
  51. externals: ['react', 'vue', 'react-dom']
  52. };

打包结果

  1. // 源文件
  2. import * as React from 'react';
  3. export default function() {
  4. const [title, setTitle] = React.useState('abc')
  5. return <div>{title}</div>
  6. }
  7. // 打包后的文件
  8. import * as React from 'react';
  9. function indexDemo () {
  10. var e = React.useState('abc'),
  11. t = e[0];
  12. return e[1], React.createElement('div', null, t)
  13. }
  14. export {
  15. indexDemo as
  16. default
  17. };

[

](https://blog.csdn.net/u011393161/article/details/107807496)