使用Import Maps导入React组件时遇React为null的Hook调用错误
问题:使用Import Maps导入React组件库时,Hook组件报错"Cannot read properties of null (reading 'useState')"
我用Vite开发项目A(可复用React组件库),目标是通过JavaScript Import Maps将组件导入到项目B中。项目A已部署生成压缩包,代码仓库也已托管。
项目A配置
vite.config.js
import { defineConfig } from 'vite' import { resolve } from 'path'; import react from '@vitejs/plugin-react' import dts from 'vite-plugin-dts' import tsconfigPaths from 'vite-tsconfig-paths' import postcssImport from 'postcss-import'; export default defineConfig({ plugins: [ tsconfigPaths(), react(), dts({ insertTypesEntry: true, }), ], css: { postcss: { plugins: [ postcssImport(), ], }, }, build: { lib: { entry: resolve(__dirname, 'src/exports.ts'), name: 'components', formats: ['es', 'cjs'], fileName: (format) => `components.${format}.js`, }, rollupOptions: { external: ['react', 'react-dom'], output: { globals: { react: 'React', 'react-dom': 'ReactDOM', }, }, }, minify: 'terser', }, define: { 'process.env.NODE_ENV': '"production"' }, })
package.json(部分)
{ ... "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { .... "@ant-design/charts": "^2.1.1", "react-grid-layout": "^1.4.4", .... } }
组件导出
import Chart from "./components/Chart/Chart"; import ButtonComponent from "./components/Button/Button"; export const LPChart = Chart; export const LPButton = ButtonComponent;
项目B集成配置
index.html(Import Maps配置)
<!doctype html> <html lang="en"> <head> ... <script type="importmap" defer> { "imports": { "react": "/node_modules/react/index.js", "react-dom": "/node_modules/react-dom/index.js", "storybook-components": "https://storybook-chart.netlify.app/dist/components.es.js" } } </script> </head> <body> <div id="root"></div> <script type="module" src="/src/main.tsx"></script> ... </body> </html>
注:试过CDN链接的React生产/开发版本,均无效:
"react": "https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.production.min.js" // prod "react": "https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js" // dev
vite.config.js
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import tsconfigPaths from 'vite-tsconfig-paths'; import path from 'path'; process.env.NODE_ENV = 'production'; export default defineConfig({ plugins: [ react(), tsconfigPaths() ], resolve: { alias: { react: path.resolve('./node_modules/react'), 'react-dom': path.resolve('./node_modules/react-dom'), "storybook-components": "http://localhost:5173/dist/components.es.js" }, }, define: { 'process.env.NODE_ENV': '"production"' }, })
package.json(部分)
{ "name": "importmappoc", ... "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" } .... }
问题现象
- 未使用React Hooks的组件可正常导入运行;
- 使用Hooks的组件导入后,控制台报错:
Warning: 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. TypeError: Cannot read properties of null (reading 'useState') at Object.useState (chunk-HZASMJ22.js?v=c5679e87:1067:29) at Button (components.es.js:10994:40) at Nh (react-dom_client.js?v=1b8ea772:3520:11) at Vk (react-dom_client.js?v=1b8ea772:6734:15) at Uk (react-dom_client.js?v=1b8ea772:6401:15) at Tk (react-dom_client.js?v=1b8ea772:6394:9) at Ik (react-dom_client.js?v=1b8ea772:6377:11) at Nk (react-dom_client.js?v=1b8ea772:6093:11) at Gk (react-dom_client.js?v=1b8ea772:6024:55) at J (react-dom_client.js?v=1b8ea772:110:21) Uncaught TypeError: Cannot read properties of null (reading 'useState') at Object.useState (chunk-HZASMJ22.js?v=c5679e87:1067:29) at Button (components.es.js:10994:40) at Nh (react-dom_client.js?v=1b8ea772:3520:11) at Vk (react-dom_client.js?v=1b8ea772:6734:15) at Uk (react-dom_client.js?v=1b8ea772:6401:15) at Tk (react-dom_client.js?v=1b8ea772:6394:9) at Ik (react-dom_client.js?v=1b8ea772:6377:11) at Nk (react-dom_client.js?v=1b8ea772:6093:11) at Gk (react-dom_client.js?v=1b8ea772:6024:55) at J (react-dom_client.js?v=1b8ea772:110:21)
错误显示组件中的React为null,没有使用项目B自身的React依赖,求解决方案。
解决方案
核心问题是组件库的ES模块未正确解析项目B提供的React依赖,导致Hooks无法找到React上下文,以下是针对性修复步骤:
1. 修正项目A的Rollup构建配置
项目A虽已将react设为external,但需明确告知Rollup保留ES模块的原始导入语句,确保能被项目B的Import Maps正确映射:
// 项目A vite.config.js -> build.rollupOptions rollupOptions: { external: ['react', 'react-dom'], output: { globals: { react: 'React', 'react-dom': 'ReactDOM', }, // 保留ES模块原始导入逻辑,不做转换 preserveModules: false, format: 'es', // 禁用interop,避免自动包裹默认导出 interop: false, }, },
2. 调整项目B的Import Maps配置
Import Maps必须指向ES模块版本的React,且移除defer确保映射在模块加载前生效:
<!-- 项目B index.html --> <script type="importmap"> { "imports": { "react": "https://cdn.jsdelivr.net/npm/react@18.2.0/esm/react.production.min.js", "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@18.2.0/esm/react-dom.production.min.js", "storybook-components": "https://storybook-chart.netlify.app/dist/components.es.js" } } </script>
3. 移除项目B中冗余的Resolve Alias
项目B的resolve.alias会优先于Import Maps解析,直接删除干扰项:
// 项目B vite.config.js -> resolve resolve: { alias: { // 删除以下冗余配置 // react: path.resolve('./node_modules/react'), // 'react-dom': path.resolve('./node_modules/react-dom'), // "storybook-components": "http://localhost:5173/dist/components.es.js" }, },
4. 验证组件库构建输出
检查项目A构建后的components.es.js,确保React导入语句为:
import React from 'react';
而非被转换为全局变量或其他形式,这样Import Maps才能正确替换路径。
5. 本地开发调试(可选)
若本地调试项目A,需启用CORS避免跨域:
// 项目A vite.config.js server: { cors: true, }
然后项目B的Import Maps指向本地开发服务器:
"storybook-components": "http://localhost:5173/dist/components.es.js"
内容的提问来源于stack exchange,提问作者Riten
相关产品推荐
相关产品推荐

