Fix the "React Hook is Called Conditionally" Error in React
Nick Scialli
March 16, 2021
If you’re new to React hooks, you might find yourself encountering this somewhat cryptic error. Let’s dive into what it is and how to fix it.
What Does It Mean?
The first rule of hooks reads as follows:
Only Call Hooks at the Top Level
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.
The TL;DR here is that you can’t use any hooks after you return
early from a component, inside a loop, or inside a conditional.
Why Does It Happen?
There’s a good chance your component looks either like this:
Example 1
function MyComponent() {
if (someCondition) {
return <p>Some information</p>;
}
useEffect(() => {
// Do something
}, []);
return <p>Some other information</p>;
}
Or like this:
Example 2
function MyComponent() {
if (someCondition) {
useEffect(() => {
// Do something
}, []);
}
return <p>Some other information</p>;
}
Or even like this:
Example 3
function MyComponent() {
myArray.forEach((el) => {
useEffect(() => {
// Do something
}, []);
});
return <p>Some other information</p>;
}
Each of these examples breaks the first rule of hooks!
- Example 1 returns early before the
useEffect
hook is called - Example 2 calls the
useEffect
hook inside a conditional - Example 3 calls the
useEffect
hook inside a loop
How To Fix The Error
The solution is a bit idosyncratic to the particular use case, but generally I see Examples 1 and 2 above a lot. Usually, you are tying to make sure an effect doesn’t run under certain conditions.
Conditionally Running Effects
Since hooks have to run on each component render, you technically can’t conditionally run a useEffect
hook. But, you can conditionally return early inside the useEffect
hook.
Let’s see how that would look.
function MyComponent() {
useEffect(() => {
if (someCondition) {
return;
}
// Do something only when `someCondition` is falsey
}, []);
return <p>Some other information</p>;
}
And that’s it— you are now running the hook on every render (as required) but you’re still able to bail out early inside that hook if you need to.
Nick Scialli is a senior UI engineer at Microsoft.