Solving "Invalid Hook Call" Errors in React
Troubleshooting Invalid Hook Calls (React Minified Error #321)
Table of contents
- Understanding the Error
- Causes of "Invalid Hook Call"
- Debugging the Error
- My Personal Example
- The 10 Rules of React Hooks (With Examples and Fixes)
- 1. Call Hooks at the Top Level
- 2. Call Hooks Only in Function Components or Custom Hooks
- 3. Use the Correct Dependencies
- 4. Create Reusable Logic With Custom Hooks
- 5. Maintain the Same Order of Hooks
- 6. Use the use Prefix for Custom Hooks
- 7. Do Not Call Hooks in Non-React Code
- 8. Avoid Hooks Inside Async Functions
- 9. Use Hooks in React Contexts
- 10. Avoid Direct State Mutation
- Takeaways
The infamous "Invalid Hook Call" error can be a massive headache, especially in complex applications using large JavaScript files. The reason this error is obnoxious is that it is found in runtime, so you will not know it exists until you run your application.
In this article, we dive into common causes for this error, some examples, and fixes.
Understanding the Error
Error Code in Development:
Invalid hook call. Hooks can only be called inside of the body of a function component.
Error Code in Production (Minified):
Minified React error #321; visit
https://reactjs.org/docs/error-decoder.html?invariant=321
This is likely one of the errors you saw in your console that led you to this article.
These errors often stem from breaking one of React’s Hook Rules, or mismanaging your React setup.
Causes of "Invalid Hook Call"
Breaking the Rules of Hooks (most common):
- See bottom of article for the 10 react hook rules
Mismatching React Versions:
- Ensure the same version of React and React DOM is used.
Duplicate React Copies:
- Happens when dependencies include their own React instance.
Calling Hooks Outside React Contexts:
- Example: Using a hook in a regular function.
Debugging the Error
Check Your Hook Placement: Ensure hooks are only used in:
React function components
Custom hooks
See bottom of article for all hook rules
Validate React Versions: Run
npm list react react-dom
to confirm versions match.Inspect for Duplicate React Copies: Run
npm ls react
to ensure only one React version is installed.Examine the Stack Trace: The browser console often points to the file and line number (roughly) causing the issue.
My Personal Example
The Problem
Here’s an example of my code that was violating the Rules of Hooks by calling useLocation()
in a regular function, which is not a React component:
export function links() {
const location = useLocation(); // ❌ Invalid Hook Call
return [{ rel: 'canonical', href: `https://example.com${location.pathname}` }];
}
Why This Fails:
- Hooks like
useLocation()
can only be called in a React function component or a custom hook, not in regular functions.
The Solution
Move the useLocation()
call to a valid React component and pass its value down:
// Corrected links function
export function links(pathname) {
return [{ rel: 'canonical', href: `https://example.com${pathname}` }];
}
// Valid React component
export default function App() {
const location = useLocation(); // ✅ Valid Hook Call
return (
<head>
<Links pathname={location.pathname} />
</head>
);
}
Why This Works:
- The
useLocation
hook is now called within a valid React component (App
), and its result is passed to thelinks
function.
The 10 Rules of React Hooks (With Examples and Fixes)
If you are getting this error, usually it is because you are breaking one of the below rules.
1. Call Hooks at the Top Level
Hooks should not be placed in conditionals or loops.
// ❌ Wrong
// Hook is placed within conditional, loop, helper function etc
if (someCondition) {
useEffect(() => { /* logic here */ }, []);
}
// ✅ Correct
useEffect(() => {
if (someCondition) {
/* logic here */
}
}, []);
2. Call Hooks Only in Function Components or Custom Hooks
Hooks cannot be used in regular JavaScript functions.
3. Use the Correct Dependencies
Include all variables used inside useEffect
or other hooks as dependencies.
// ❌ Wrong
useEffect(() => {
console.log(count); // count is missing in dependencies
}, []);
// ✅ Correct
useEffect(() => {
console.log(count);
}, [count]);
4. Create Reusable Logic With Custom Hooks
Extract shared logic into custom hooks.
// ✅ Custom Hook
function useFetchData(url) {
const [data, setData] = useState();
useEffect(() => {
fetch(url).then(response => response.json()).then(setData);
}, [url]);
return data;
}
This is more so advice than a rule, but it will massively clean up your code if you understand how to abstract reused logic into your React hooks.
5. Maintain the Same Order of Hooks
The order of hooks must be consistent. Here are some ways hooks can remain inconsistent:
Using hooks in conditionals, loops or functions
Dynamically loading components that contain hooks (based on screen size, variables etc)
Returning from a function before a potential hook call
// Hook usage inside a conditional (WRONG)
// ❌ Hook skips when `isMobile` is false
if (isMobile) {
useEffect(() => {
console.log("This runs only if isMobile is true.");
}, [isMobile]);
}
// Hook usage inside a loop (WRONG)
// ❌ Hook order depends on the array length and iteration
items.forEach((item) => {
useState(item);
});
// Hook usage inside a nested function (WRONG)
// ❌ Hook order breaks because it's inside a function
function handleNested() {
useState('nested');
}
if (items.length > 3) {
handleNested();
}
// Dynamically loaded components based on screen size or conditions (WRONG)
// ❌ Hook order changes dynamically
if (isMobile) {
useEffect(() => {
console.log("Conditional rendering logic with hooks");
}, []);
}
// Returning early from the component before a hook call (WRONG)
// ❌ Skips subsequent hooks
if (!items || items.length === 0) {
return <div>No items</div>;
// hook would be in function under this conditional
}
// Correct usage
// ✅ Conditional logic inside the hook
useEffect(() => {
if (isMobile) {
console.log("Do something when isMobile is true.");
}
}, [isMobile]);
6. Use the use
Prefix for Custom Hooks
This helps distinguish hooks from regular functions.
// ✅ Custom Hook
function useCustomHook() {
return useState();
}
7. Do Not Call Hooks in Non-React Code
Avoid using hooks in unrelated files or external utilities.
8. Avoid Hooks Inside Async Functions
Hooks cannot be called within asynchronous code directly.
// ❌ Wrong
useEffect(async () => {
const data = await fetchData();
}, []);
// ✅ Correct
useEffect(() => {
fetchData().then(data => setData(data));
}, []);
9. Use Hooks in React Contexts
Hooks like useContext
require a valid context provider.
// ✅ Correct
const MyContext = React.createContext();
function MyComponent() {
const value = useContext(MyContext); // Valid
}
10. Avoid Direct State Mutation
React state must be updated using the setState
function.
// ❌ Wrong
state.value = 42;
// ✅ Correct
setState({ value: 42 });
Takeaways
When debugging an "Invalid Hook Call" error:
Check your hook usage against React’s Hook Rules.
Validate your project setup for version mismatches or duplicate React copies.
Review stack traces and error messages for insights.
By following this guide, you can avoid this error, and ensure smooth development in your React projects.