How to fix Hook can only be called inside the body of a function component in React
This ESLint error occurs when React Hooks (like useState, useEffect) are called outside function components or custom hooks, or not at the top level. React requires hooks to follow strict rules about where and how they can be called to maintain state consistency.
Quick fix
Fixes Hook can only be called inside the body of a function component
function MyComponent({ isLoggedIn }) {
if (isLoggedIn) {
const [user, setUser] = useState(null); // ❌ Hook in conditional
}
return <div>Content</div>;
}- Move hooks to the top level of your function component
- Move hooks out of event handlers and callbacks
- Convert utility functions to custom hooks
- Remove hooks from loops
function MyComponent({ isLoggedIn }) {if (isLoggedIn) {const [user, setUser] = useState(null); // ❌ Hook in conditional}return <div>Content</div>;}Hook can only be called inside the body of a function component
What this error means
This error is triggered by the eslint-plugin-react-hooks rules-of-hooks rule when you violate the Rules of Hooks. React Hooks must be called in specific locations to work correctly. React Hooks rely on a consistent call order to maintain state between renders. When you call hooks in conditional statements, loops, nested functions, or outside of React components, React cannot guarantee this consistency, leading to bugs and unpredictable behavior. The Rules of Hooks are enforced by ESLint to catch these issues during development before they cause runtime errors. This rule helps ensure your components follow React's internal assumptions about how hooks work.
Typical symptoms
- ESLint error "React Hook is called in function that is neither a React function component nor a custom React Hook function"
- ESLint warning with rule ID "react-hooks/rules-of-hooks"
- Hooks being called inside event handlers or callbacks
- Hooks appearing inside conditional statements or loops
- Custom functions using hooks without "use" prefix
- Class components attempting to use hooks
Common causes
- Calling hooks inside regular JavaScript functions instead of React components
- Placing hooks inside conditional statements (if/else, switch, ternary operators)
- Using hooks within loops (for, while, map callbacks)
- Calling hooks inside event handlers or other callbacks
- Attempting to use hooks in class components
- Custom hook functions not starting with "use" prefix
- Calling hooks inside functions passed to useMemo, useCallback, or useEffect
- Nested function definitions that call hooks
- Calling component functions directly instead of rendering them with JSX
How to fix "Hook can only be called inside the body of a function component"
Ensure all hooks are called at the top level of your component, before any early returns or conditional logic.
❌ Incorrect - Hook inside condition:
function MyComponent({ isLoggedIn }) {
if (isLoggedIn) {
const [user, setUser] = useState(null); // ❌ Hook in conditional
}
return <div>Content</div>;
}✅ Correct - Hook at top level:
function MyComponent({ isLoggedIn }) {
const [user, setUser] = useState(null); // ✅ Hook at top level
if (!isLoggedIn) {
return <div>Please log in</div>;
}
return <div>Welcome {user?.name}</div>;
}Don't call hooks inside event handlers, timers, or other callback functions. Instead, call them at the component's top level and use the values in callbacks.
❌ Incorrect - Hook in event handler:
function MyComponent() {
const handleClick = () => {
const [count, setCount] = useState(0); // ❌ Hook in callback
setCount(count + 1);
};
return <button onClick={handleClick}>Click</button>;
}✅ Correct - Hook at top level:
function MyComponent() {
const [count, setCount] = useState(0); // ✅ Hook at top level
const handleClick = () => {
setCount(count + 1); // ✅ Use state setter in callback
};
return <button onClick={handleClick}>Count: {count}</button>;
}If you have a regular function that needs to use hooks, convert it to a custom hook by prefixing the name with "use" and ensuring it's called from a component.
❌ Incorrect - Regular function with hooks:
function fetchUserData(userId) {
const [data, setData] = useState(null); // ❌ Hook in regular function
useEffect(() => {
// fetch logic
}, [userId]);
return data;
}
function MyComponent({ userId }) {
const userData = fetchUserData(userId); // ❌ Calling regular function
return <div>{userData}</div>;
}✅ Correct - Custom hook:
function useFetchUserData(userId) { // ✅ "use" prefix makes it a hook
const [data, setData] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(setData);
}, [userId]);
return data;
}
function MyComponent({ userId }) {
const userData = useFetchUserData(userId); // ✅ Calling custom hook
return <div>{userData}</div>;
}Never call hooks inside loops. If you need multiple state values, call useState multiple times or use a single state object/array.
❌ Incorrect - Hooks in loop:
function MyComponent({ items }) {
const states = [];
items.forEach(item => {
states.push(useState(item)); // ❌ Hook in loop
});
return <div>...</div>;
}✅ Correct - Single state for array:
function MyComponent({ items }) {
const [itemStates, setItemStates] = useState(items); // ✅ Single hook
return (
<div>
{itemStates.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
);
}React treats functions starting with uppercase letters as components. If your function uses hooks, it must start with a capital letter or "use".
❌ Incorrect - lowercase component with hooks:
function myComponent() { // ❌ lowercase name
const [value, setValue] = useState(''); // Hook in non-component function
return <input value={value} onChange={e => setValue(e.target.value)} />;
}✅ Correct - Capitalized component:
function MyComponent() { // ✅ Capitalized name
const [value, setValue] = useState('');
return <input value={value} onChange={e => setValue(e.target.value)} />;
}Ensure you have the React Hooks ESLint plugin installed to catch these issues during development.
Install the plugin:
npm install eslint-plugin-react-hooks --save-devConfigure in .eslintrc.json:
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}This plugin is included by default in Create React App and many React frameworks.
Advanced notes
Why the Rules of Hooks exist:
React Hooks rely on a stable call order across renders. React internally maintains a list of hooks for each component instance, and uses the order of hook calls to associate state with the correct useState or useEffect call. If hooks are called conditionally or in loops, this order can change between renders, causing React to lose track of which state belongs to which hook.
Custom hooks naming:
Custom hooks must start with "use" (e.g., useFetchData, useAuth) for two reasons: (1) it signals to ESLint that the function can call other hooks, and (2) it communicates to other developers that the function follows the Rules of Hooks and should only be called from components or other custom hooks.
Class components and hooks:
Hooks are fundamentally incompatible with class components because they rely on functional component rendering behavior. If you need to use hooks in a class component, you must either refactor the class to a function component or extract the hook logic into a custom hook and pass the values as props.
ESLint limitations:
The rules-of-hooks ESLint rule uses static analysis and can sometimes produce false positives. For example, if you dynamically generate component names or use non-standard patterns, ESLint might incorrectly flag valid code. In rare cases, you can disable the rule for specific lines, but ensure your code actually follows the Rules of Hooks first.
Multiple React instances:
If you have multiple copies of React in your node_modules (often due to npm link or conflicting dependencies), hooks may fail at runtime even if ESLint doesn't complain. Use npm ls react or yarn why react to check for duplicate React installations.
Frequently asked questions
- What does "Hook can only be called inside the body of a function component" mean?
- This error is triggered by the eslint-plugin-react-hooks rules-of-hooks rule when you violate the Rules of Hooks. React Hooks must be called in specific locations to work correctly. React Hooks rely on a consistent call order to maintain state between renders.
- How do I fix "Hook can only be called inside the body of a function component"?
- This ESLint error occurs when React Hooks (like useState, useEffect) are called outside function components or custom hooks, or not at the top level. React requires hooks to follow strict rules about where and how they can be called to maintain state consistency.
- What causes "Hook can only be called inside the body of a function component"?
- Calling hooks inside regular JavaScript functions instead of React components Placing hooks inside conditional statements (if/else, switch, ternary operators) Using hooks within loops (for, while, map callbacks)
- Is the "Hook can only be called inside the body of a function component" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚React Official Documentation
- 🔗
- 🔗
- 📖legacy.reactjs.org - hooks rules(Official Docs)
- 🔗