A strong invalid hook call note must separate rule-of-hooks mistakes from dependency problems. The warning can come from code structure, such as calling useState in a normal function, or from package structure, such as two React copies being loaded.
Debugging should move in two passes: first inspect the component code for hook placement, then inspect node_modules and package versions for duplicate React or mismatched react/react-dom.
The "Invalid hook call" warning occurs when React Hooks are called in an invalid context. This typically happens due to mismatched React versions, duplicate React installations, calling Hooks outside React components, or breaking the Rules of Hooks.
# Check for duplicate React
npm ls react
# Fix duplicate React
npm dedupe
# or
rm -rf node_modules package-lock.json
npm install
# Ensure matching versions
npm install react@latest react-dom@latest
The most common cause "" having multiple copies of React in your project.
# Check for multiple React versions
npm ls react
# or
yarn why react
# You might see:
# ├── react@18.2.0
# └─┬ some-library@1.0.0
# └── react@17.0.2 ← Duplicate!
# Solution 1: Dedupe
npm dedupe
# Solution 2: Clean install
rm -rf node_modules package-lock.json
npm install
# Solution 3: Use resolutions (package.json)
{
"resolutions": {
"react": "18.2.0",
"react-dom": "18.2.0"
}
}
# Solution 4: Use overrides (npm 8.3+)
{
"overrides": {
"react": "18.2.0",
"react-dom": "18.2.0"
}
}
// package.json
{
"dependencies": {
"react": "18.2.0",
"react-dom": "17.0.2" // ❌ Mismatched version!
}
}
# Install matching versions
npm install react@18.2.0 react-dom@18.2.0
# Or use latest for both
npm install react@latest react-dom@latest
// ❌ Regular function, not a component
function fetchData() {
const [data, setData] = useState(null); // Invalid hook call!
// ...
}
// ❌ Called outside component
const data = useState(null); // Invalid hook call!
function App() {
return <div>{data}</div>;
}
// ✅ Create a custom hook (starts with "use")
function useFetchData() {
const [data, setData] = useState(null);
// ...
return data;
}
// ✅ Call hooks inside component
function App() {
const [data, setData] = useState(null); // ✅ Inside component
return <div>{data}</div>;
}
# When developing a library with npm link
cd my-library
npm link
cd ../my-app
npm link my-library # Creates duplicate React!
# Link React from the app to the library
cd my-app/node_modules/react
npm link
cd ../react-dom
npm link
cd ../../../my-library
npm link react react-dom
# Or use peerDependencies in library
{
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
}
Hooks must run at the top level of a React function component or inside another custom hook. React depends on the order of hook calls staying the same on every render. If a hook is called inside a condition, loop, callback, class component, or normal utility function, React cannot reliably match hook state to the right call.
Custom hooks are allowed because they are part of the React render flow, but they must also follow the same rule. The custom hook name should start with use, and the hook should be called unconditionally by a component or another hook.
React hooks rely on one shared React module instance. If your app imports React from one copy and React DOM renders with another copy, hook internals do not match and React shows the invalid hook call warning.
This often happens with npm link, local component libraries, monorepos, or dependencies that incorrectly list react as a dependency instead of a peer dependency. The fix is to make the app and linked package resolve to the same React copy.
import { useState } from "react";
function readCounter() {
const [count] = useState(0); // Wrong: not a component or custom hook
return count;
}
import { useState } from "react";
function useCounter() {
const [count, setCount] = useState(0);
return { count, setCount };
}
export default function Counter() {
const { count, setCount } = useCounter();
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Calling useState inside a helper function.
Create a custom hook or move state into a component.
Checking only source code and ignoring dependencies.
Check duplicate React versions too.
Putting hooks after an early return.
Call hooks before conditional returns.
The most common causes are: duplicate React installations in node_modules, mismatched React and React-DOM versions, calling Hooks outside React components, or breaking the Rules of Hooks.
Run npm ls react or yarn why react in your terminal. If you see multiple versions listed, you have duplicate React installations that need to be resolved.
Try npm dedupe first. If that doesn't work, delete node_modules and package-lock.json, then run npm install. You can also use resolutions or overrides in package.json to force a single React version.
No. Hooks can only be called inside React function components or custom hooks (functions starting with "use"). Regular utility functions cannot use Hooks.
npm link can create duplicate React installations because the linked library has its own node_modules with React. Link React from your app to your library to share the same React instance.
Explore 500+ free tutorials across 20+ languages and frameworks.