基于Rollup构建React组件库时useState触发无效Hook调用错误求助
I’ve run into this exact issue multiple times when building React component libraries for Next.js—let’s break down what’s going wrong and how to fix it, based on your configuration and scenario.
Core Issue: Duplicate React Instances or Misconfigured Rollup
The Invalid hook call error here is almost certainly tied to multiple copies of React being loaded (once by your component library, once by Next.js) or Rollup not properly externalizing React as a peer dependency. Your npm link fix worked for Webpack/microbundle, but Rollup needs a slightly different approach.
Step 1: Fix Rollup Configuration
Looking at your rollup.config.js, there are two key issues with how you’re handling external dependencies:
- Incorrect usage of
rollup-plugin-peer-deps-external: The plugin automatically reads yourpackage.json’speerDependencies—you don’t need to pass./package.jsonto it. - Missing deduplication for React: Add
dedupeto the resolve plugin to force Rollup to use a single version of React.
Here’s the corrected config:
import babel from 'rollup-plugin-babel' import commonjs from 'rollup-plugin-commonjs' import resolve from 'rollup-plugin-node-resolve' import peerDepsExternal from 'rollup-plugin-peer-deps-external' import { terser } from 'rollup-plugin-terser' import styles from "rollup-plugin-styles"; const input = 'src/index.js' const output = 'dist/index' export default [ { input: input, external: ['react', 'react-dom'], // Explicitly mark as external output: [ { file: `${output}.modern.js`, format: 'es', }, { file: `${output}.js`, format: 'cjs', // Add CommonJS output for better Next.js compatibility } ], plugins: [ peerDepsExternal(), // Auto-detect peerDependencies from package.json resolve({ dedupe: ['react', 'react-dom'], // Critical: Force single React instance }), commonjs({ include: ['node_modules/**'] }), babel({ exclude: 'node_modules/**', presets: ['@babel/preset-react'] // Ensure React preset is enabled }), styles(), terser() ], }, ]
Step 2: Eliminate Duplicate React Copies When Using npm link
When linking your local library to Next.js, it’s easy for both projects to load their own React instance. Fix this by:
- In your component library:
- Delete
node_modules/reactandnode_modules/react-dom(since they’re inpeerDependencies, you don’t need local copies for production; keep them indevDependenciesfor local development).
- Delete
- In your Next.js project:
- Run this command to force Next.js to use the same React instance as your library:
npm link ../path-to-your-library/node_modules/react - Alternatively, you can link your library’s React to Next.js’s copy—either way ensures only one React instance is loaded.
- Run this command to force Next.js to use the same React instance as your library:
Step 3: Configure Next.js to Resolve React Correctly
Next.js’s dev mode caching can sometimes cause duplicate module loads. Add this to your Next.js project’s next.config.js to enforce a single React instance:
const path = require('path'); module.exports = { webpack: (config) => { config.resolve.alias = { ...config.resolve.alias, 'react': path.resolve(__dirname, './node_modules/react'), 'react-dom': path.resolve(__dirname, './node_modules/react-dom'), }; return config; }, };
Step 4: Double-Check Hook Usage Rules
Even if your config is fixed, make sure your components follow Hook rules strictly:
- Hooks like
useStateare called only at the top level of function components (no conditionals, loops, or nested functions). - You’re not using Hooks in class components.
- All custom Hooks start with
use(e.g.,useMyCustomHook).
Step 5: Clean Caches and Rebuild
Old build artifacts or node_modules can cause lingering issues. Run these commands in order:
- Component library:
rm -rf dist node_modules npm install npm run build - Next.js project:
rm -rf .next node_modules npm install npm link your-library-name
内容的提问来源于stack exchange,提问作者Igor Paiva Ferreira

