React+Material UI项目出现Invalid hook call错误求助
React Invalid Hook Call 错误排查与解决
错误信息
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. React 2 useTheme useTheme.js:4 useTheme useThemeWithoutDefault.js:9 useTheme useTheme.js:7 Box createBox.js:22 React 17 js index.js:8 factory react refresh:6 Webpack 3 react.development.js:1447 React 2 useTheme useTheme.js:4 useTheme useThemeWithoutDefault.js:9 useTheme useTheme.js:7 Box createBox.js:22 React 17 js index.js:8 factory react refresh:6 Webpack 3 __webpack_require__ <anonymous> <anonymous>
项目结构说明
项目包含两个独立部分:Components(React组件库)和Onboarding(业务项目),Onboarding通过本地路径../../Components/dist引入Components作为依赖。
Components 目录配置
根目录 package.json
{ "name": "My Project", "version": "2.0.0", "description": "Main React Library", "main": "dist/index.js", "module": "dist/index.js", "bundleDependencies": false, "deprecated": false, "license": "MIT", "private": true, "sideEffects": false, "scripts": { "build": "rm -rf dist && NODE_ENV=production babel src --out-dir dist --copy-files" }, "devDependencies": { "@babel/cli": "^7.18.10", "@babel/core": "^7.18.10", "@babel/plugin-syntax-flow": "^7.18.6", "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.18.10", "@babel/preset-flow": "^7.18.6", "@babel/preset-react": "^7.18.6", "@types/node": "^18.7.15", "typescript": "^4.8.2", "reactstrap": "^9.1.4", "react-quill": "^2.0.0" }, "dependencies": {} }
src 目录 package.json
{ "name": "My Project", "version": "2.0.0", "description": "Main React Library", "main": "index.js", "module": "index.js", "bundleDependencies": false, "deprecated": false, "license": "MIT", "private": true, "sideEffects": false, "dependencies": { "@mui/icons-material": "5.4.1", "@mui/material": "5.4.1", "@mui/styled-engine": "5.4.1", "react": "17.0.2", "react-dom": "17.0.2", "react-router-dom": "6.2.1", "axios": "^0.27.2", "uuid": "^9.0.0", "bootstrap": "^5.2.0" } }
Onboarding 目录配置
根目录 package.json
{ "name": "onboarding-ui", "description": "", "version": "0.1.0", "scripts": { "start": "sls offline --aws-profile", "deploy": "sls deploy -s stage --aws-profile", "test": "sls invoke test" }, "devDependencies": { "aws-sdk-mock": "^5.7.0", "serverless": "^3.21.0", "serverless-cloudfront-invalidate": "^1.11.0", "serverless-latest-layer-version": "^2.1.1", "serverless-mocha-plugin": "^1.12.0", "serverless-offline": "^6.8.0", "serverless-prune-plugin": "^1.4.3", "serverless-s3-sync": "^1.14.4", "serverless-scriptable-plugin": "^1.0.5" } }
src 目录 package.json
{ "name": "onboarding", "version": "0.2.17", "private": true, "author": "Me", "license": "MIT", "description": "presentation layer.", "engines": { "node": "14 || 15 || 16", "npm": ">=6" }, "dependencies": { "@asseinfo/react-kanban": "2.2.0", "@emotion/cache": "11.7.1", "@emotion/react": "11.7.1", "@emotion/styled": "11.6.0", "@mui/icons-material": "5.4.1", "@mui/material": "5.4.1", "@mui/styled-engine": "5.4.1", "@mui/styles": "^5.9.2", "@react-jvectormap/core": "1.0.1", "@react-jvectormap/world": "1.0.0", "@testing-library/jest-dom": "5.16.2", "@testing-library/react": "12.1.2", "@testing-library/user-event": "13.5.0", "accounted-ui": "../../Components/dist", "axios": "^0.27.2", "chart.js": "3.4.1", "chroma-js": "2.4.2", "crypto-js": "^4.1.1", "dropzone": "5.9.2", "flatpickr": "4.6.9", "formik": "^2.2.9", "html-react-parser": "1.4.8", "i18next": "^21.9.1", "i18next-browser-languagedetector": "^6.1.5", "i18next-http-backend": "^1.4.1", "lodash.debounce": "^4.0.8", "prop-types": "15.8.1", "react": "17.0.2", "react-chartjs-2": "3.0.4", "react-confetti": "^6.1.0", "react-csv": "^2.2.2", "react-debounce-input": "^3.3.0", "react-dom": "17.0.2", "react-flatpickr": "3.10.7", "react-github-btn": "1.2.1", "react-i18next": "^11.18.5", "react-images-viewer": "1.7.1", "react-quill": "1.3.5", "react-router-dom": "6.2.1", "react-scripts": "5.0.0", "react-table": "7.7.0", "react-toastify": "^9.0.3", "stylis": "4.0.13", "uuid": "8.3.2", "web-vitals": "2.1.4", "yup": "^0.32.11" }, "scripts": { "start": "react-scripts start", "build:dev": "dotenv -e .env.dev react-scripts build", "build:prod": "dotenv -e .env.prod react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "install:clean": "rm -rf node_modules/ && rm -rf package-lock.json && npm install" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "accounted-ui": "../../Components/dist", // this is how I'm pulling in the `Components` folder "dotenv-cli": "^5.1.0", "eslint": "8.8.0", "eslint-config-airbnb": "19.0.4", "eslint-config-prettier": "8.3.0", "eslint-plugin-import": "2.25.4", "eslint-plugin-jsx-a11y": "6.5.1", "eslint-plugin-prettier": "4.0.0", "eslint-plugin-react": "7.28.0", "eslint-plugin-react-hooks": "4.3.0", "prettier": "2.5.1" } }
问题分析与修复方案
核心问题
错误根源是项目中存在多份React实例:Components/src/package.json将react、react-dom放在dependencies中,构建后会被打包进dist目录;Onboarding自身也依赖React,导致运行时加载两个不同的React实例,Material UI的useTheme Hook跨实例调用触发错误。
修复步骤
1. 重构Components的依赖配置
- 删除
Components/src/package.json,将其中的依赖合并到根目录package.json。 - 将
react、react-dom、@mui相关包移到peerDependencies(组件库不应自带React,需由宿主项目提供统一版本),同时在devDependencies中保留这些包用于开发:
// Components根目录package.json { // ...原有配置 "peerDependencies": { "@mui/icons-material": "5.4.1", "@mui/material": "5.4.1", "@mui/styled-engine": "5.4.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-router-dom": "^6.2.1" }, "devDependencies": { // ...原有devDependencies "@mui/icons-material": "5.4.1", "@mui/material": "5.4.1", "@mui/styled-engine": "5.4.1", "react": "17.0.2", "react-dom": "17.0.2", "react-router-dom": "6.2.1" } }
- 执行
npm install和npm run build,确保dist目录不包含React相关代码。
2. 清理Onboarding的重复依赖
- 删除
Onboarding/src/package.json中devDependencies里的accounted-ui,仅保留dependencies中的声明,避免重复引入。
3. 强制统一React版本
若上述步骤后仍有问题,在Onboarding/src/package.json中添加resolutions(npm需配合npm-force-resolutions工具,yarn直接支持):
{ "resolutions": { "react": "17.0.2", "react-dom": "17.0.2" } }
- 清理两个项目的
node_modules和package-lock.json,重新执行npm install。
4. 验证修复
启动Onboarding项目,检查错误是否消失。
内容的提问来源于stack exchange,提问作者Mustafa Yusuf
相关产品推荐
相关产品推荐

