TypeOfNaN

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

Nick Scialli March 16, 2021🚀 3 minute read

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.

If you'd like to support this blog by buying me a coffee I'd really appreciate it!

Nick Scialli is a software engineer at the U.S. Digital Service.