通过绝对路径安装React UI包时出现useState读取null属性错误
问题根源
这个错误的核心是React重复加载:当通过npm link或本地绝对路径安装组件包时,组件包和你的Vite宿主项目会各自加载一份独立的React实例。React Hooks要求必须在同一个React实例的上下文里调用,多个实例共存会导致Hook调用失效,抛出Cannot read properties of null (reading 'useState')这类错误。
而通过npm pack或远程仓库安装时,组件包的node_modules不会被安装到宿主项目中,React会直接复用宿主项目的实例,因此不会出现冲突。
解决方案
1. 确保React仅作为Peer依赖
检查组件包package.json,确保React和React DOM只出现在peerDependencies和devDependencies中,绝对不能在dependencies里:
{ "peerDependencies": { "react": "^18.0.0", "react-dom": ">=16.6.0" }, "devDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" } }
这样本地安装时,npm不会为组件包单独安装React,而是复用宿主项目的版本。
2. 配置Vite强制复用宿主项目的React
在宿主项目的vite.config.js中添加别名配置,强制所有React相关导入指向宿主项目的node_modules:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; import path from 'path'; export default defineConfig({ plugins: [react()], resolve: { alias: { 'react': path.resolve(__dirname, 'node_modules/react'), 'react-dom': path.resolve(__dirname, 'node_modules/react-dom') } } });
这个配置会让组件包中的React导入直接使用宿主项目的实例,避免重复加载。
3. 优化Rollup的External配置
将Rollup的external配置从模糊的正则/node_modules/改为明确指定peer依赖,确保React相关包被正确标记为外部依赖:
external: ['react', 'react-dom'],
配合peerDepsExternal插件使用,能更精准地排除peer依赖,避免打包时误包含React代码。
4. npm link场景的临时修复(可选)
如果必须使用npm link,可以在宿主项目中手动链接组件包的React到宿主项目:
# 在组件包目录执行 npm link # 在宿主项目目录执行 npm link your-component-package npm link ../your-component-package/node_modules/react
不过这种方法需要每次链接都操作,不如Vite别名配置持久可靠。
内容的提问来源于stack exchange,提问作者am guru prasath

