The "Invalid hook call" warning occurs when React Hooks are called outside of a function component or custom Hook, when there are mismatching versions of React and ReactDOM, or when multiple copies of React exist in the same application.
This warning is React's way of enforcing the Rules of Hooks, which state that Hooks must be called at the top level of function components or custom Hooks. React uses an internal tracking system to maintain state and effects across renders. When Hooks are called from invalid contexts (like class components, regular JavaScript functions, or event handlers), React loses the ability to properly track and manage component state. The error can also stem from technical issues in your project setup. If you have multiple versions of React installed or if your React and ReactDOM versions don't match, each version maintains its own separate context tree. When a component from one context tree tries to use a Hook from another, React can't establish the necessary connection. This is one of the most common errors developers encounter when adopting Hooks, because it represents a fundamental shift from class-based patterns to functional patterns. Understanding this error is essential for writing robust React applications.
Check that your Hook calls are directly in the body of a function component, not inside conditions, loops, or nested functions:
// ❌ WRONG - Hook inside condition
function MyComponent() {
if (someCondition) {
const [state, setState] = useState(0); // Invalid!
}
}
// ❌ WRONG - Hook in event handler
function MyComponent() {
const handleClick = () => {
const [state, setState] = useState(0); // Invalid!
};
}
// ✅ CORRECT - Hook at top level
function MyComponent() {
const [state, setState] = useState(0);
if (someCondition) {
// Use the state here
}
}All Hooks must be called in the same order on every render, which is why they must be at the top level.
Ensure you're not trying to use Hooks inside class components or regular functions:
// ❌ WRONG - Hook in class component
class MyComponent extends React.Component {
render() {
const [state, setState] = useState(0); // Invalid!
return <div>{state}</div>;
}
}
// ❌ WRONG - Hook in regular function
function myUtilityFunction() {
const [state, setState] = useState(0); // Invalid!
return state;
}
// ✅ CORRECT - Hook in function component
function MyComponent() {
const [state, setState] = useState(0);
return <div>{state}</div>;
}
// ✅ CORRECT - Hook in custom Hook
function useCustomHook() {
const [state, setState] = useState(0);
return state;
}Function component names and custom Hook names must start with an uppercase letter or "use" respectively.
Check your package.json to ensure react and react-dom have matching versions:
npm ls react
npm ls react-domIf versions don't match, update both to the same version:
npm install [email protected] [email protected]Or use npm update to sync versions:
npm update react react-domAfter updating, delete node_modules and reinstall:
rm -rf node_modules package-lock.json
npm installRun npm ls to see if multiple versions of React are installed:
npm ls reactIf you see duplicate versions, check which packages are bringing in different React versions. You may need to:
1. Update dependencies that require older React versions
2. Use npm dedupe to flatten the dependency tree:
npm dedupe3. Add resolutions in package.json (for Yarn) or overrides (for npm 8.3+):
{
"overrides": {
"react": "18.2.0",
"react-dom": "18.2.0"
}
}If you're using npm link for local development, this commonly causes duplicate React issues. Use proper module resolution or absolute imports instead.
Temporarily add this code to verify you're using the same React instance:
import React from 'react';
import ReactDOM from 'react-dom';
// Add to your entry file (index.js/main.jsx)
window.React1 = React;
console.log('React instance:', React);
// Then in your component file
import React from 'react';
window.React2 = React;
console.log('Same instance?', window.React1 === window.React2);If this logs false, you have multiple React copies. Check your webpack/vite config to ensure React resolves to a single path:
// webpack.config.js
module.exports = {
resolve: {
alias: {
react: path.resolve('./node_modules/react'),
'react-dom': path.resolve('./node_modules/react-dom')
}
}
};Ensure custom Hooks follow the naming convention (must start with "use") and are called correctly:
// ❌ WRONG - doesn't start with "use"
function myCustomHook() {
const [state, setState] = useState(0); // May cause issues
return state;
}
// ✅ CORRECT - proper custom Hook
function useMyCustomHook() {
const [state, setState] = useState(0);
return state;
}
// ✅ CORRECT - using the custom Hook
function MyComponent() {
const value = useMyCustomHook(); // Valid
return <div>{value}</div>;
}The "use" prefix tells React's linter that this function contains Hooks and should follow Hook rules.
Install and configure eslint-plugin-react-hooks to catch Hook rule violations during development:
npm install --save-dev eslint-plugin-react-hooksAdd to your .eslintrc.js:
module.exports = {
plugins: ['react-hooks'],
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
}
};This plugin will highlight invalid Hook calls as you write code, preventing the error before runtime.
If you're working with a monorepo or using npm/yarn workspaces, duplicate React instances are especially common. Tools like Lerna, Yarn workspaces, or pnpm can create situations where different packages resolve to different React copies. Use the "nohoist" option in workspaces or configure your bundler to resolve React from a single location.
When building React libraries that will be consumed by other applications, make sure to mark react and react-dom as peerDependencies, not dependencies. This prevents your library from bundling its own React copy:
{
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
}
}For micro-frontend architectures or module federation, ensure shared modules are properly configured to avoid multiple React instances across different bundles. This is critical in webpack Module Federation setups.
Prop spreading could cause security issues
Prop spreading could cause security issues
Error: error:0308010C:digital envelope routines::unsupported
Error: error:0308010C:digital envelope routines::unsupported
React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.
React Hook useEffect placed inside a condition
Hook can only be called inside the body of a function component
Hook can only be called inside the body of a function component
Rollup failed to resolve import during build
How to fix "Rollup failed to resolve import" in React