在封装 React 组件库后,不同 React 版本的项目引入可能会遇到 版本冲突 、hooks 失效 或 多个 React 实例 导致 Invalid Hook Call
错误。这些问题通常是因为 react
和 react-dom
版本不兼容,或组件库与项目各自持有独立的 React 依赖。
一. 问题分析
常见问题
-
Invalid Hook Call Warning
- 组件库与项目持有不同的 React 版本,导致 Hooks 失效。
-
多个 React 实例导致状态不共享
- 组件库可能安装了自己的
react
,导致项目和库运行在不同的 React 作用域内。
- 组件库可能安装了自己的
-
版本不兼容
- 项目使用了较新的 React 版本,而组件库使用了较老的 React 版本(或反之)。
二. 解决方案
方案 1:组件库 peerDependencies
处理 React 版本
👉 确保组件库不直接安装 React,而是使用 peerDependencies
在 package.json
中,调整 peerDependencies
,确保库不安装自己的 react
,而是使用宿主项目的 React 版本:
json
json
复制编辑
{
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
📌 解释:
peerDependencies
让项目 必须 提供 React 版本,而不是组件库自己安装。devDependencies
仅用于开发组件库时的 React 版本,不会被打包。
方案 2:确保宿主项目和组件库使用同一个 React 实例
👉 避免组件库重复安装 React,可以通过 resolve.alias
或 yarn link
解决
方式 1:Webpack resolve.alias
确保 react
版本统一 如果项目和组件库安装了不同的 React 版本,可以在 Webpack 配置 中强制让 react
解析到宿主项目的 node_modules
:
css
js
复制编辑
module.exports = {
resolve: {
alias: {
react: require.resolve("react"), // 强制使用宿主项目的 react
"react-dom": require.resolve("react-dom")
}
}
};
方式 2:Yarn / npm link 让库复用 React
-
在宿主项目中运行:
bashsh 复制编辑 yarn link react yarn link react-dom
-
在组件库中运行:
bashsh 复制编辑 yarn link
方案 3:使用 externals
让打包时不包含 React
👉 如果组件库使用 Webpack / Rollup 打包,应该把 react
标记为 external
Webpack
css
js
复制编辑
module.exports = {
externals: {
react: "react",
"react-dom": "react-dom"
}
};
Rollup
dart
js
复制编辑
export default {
external: ["react", "react-dom"]
};
📌 效果:
- 组件库打包时不会把
react
代码包含进去,而是使用宿主项目的react
。
3. 终极方案
如果还是有兼容性问题,可以:
-
强制升级项目 React 版本,确保和组件库版本一致:
sqlsh 复制编辑 npm dedupe npm update react react-dom
-
改用
umd
构建输出,提供兼容性更好的模块格式:cssjson 复制编辑 { "main": "dist/index.js", "module": "dist/index.esm.js", "unpkg": "dist/index.umd.js" }
4. 总结
方案 | 解决方案 | 适用情况 |
---|---|---|
peerDependencies |
让组件库不安装 React,而是依赖项目的 React | 最佳方案,适用于所有情况 |
Webpack resolve.alias |
强制所有 React 指向同一个实例 | 适用于 Webpack 项目 |
Yarn / npm link | 让项目和组件库共享 react |
开发环境调试时适用 |
externals 处理打包 |
让组件库打包时不包含 react |
适用于组件库打包发布 |
推荐方案:使用
peerDependencies
+externals
处理 React 依赖!