TypeOfNaN

Fix the "React Hook is Called Conditionally" Error in React

Nick Scialli
March 16, 2021

New — Check out my free newsletter on how the web works!

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.

🎓 Learn how the web works

One of the best ways to level up your tech career is to have a great foundational understanding of how the web works. In my free newsletter, How the Web Works, I provide simple, bite-sized explanations for various web topics that can help you boost your knowledge. Join 2,500+ other learners on the newsletter today!

Signing up is free, I never spam, and you can unsubscribe any time. You won't regret it!

Sign up for the newsletter »
Nick Scialli

Nick Scialli is a senior UI engineer at Microsoft.

© 2024 Nick Scialli