Rendered more hooks than during the previous render (React)

avatar

Borislav Hadzhiev

Last updated: Jul 25, 2022

banner

Photo from Unsplash

Rendered more hooks than during the previous render (React) #

The error "Rendered more hooks than during the previous render" occurs when we conditionally call a hook or return early before all hooks have ran. To solve the error, move all hooks at the top level of the function component and don't use hooks inside conditions.

rendered more hooks than during previous render

Here is an example of how the error occurs.

App.js
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); // ⛔️ Error: Rendered more hooks than during the previous render. if (counter > 0) { // 👇️ calling React hook conditionally useEffect(() => { console.log('hello world'); }); } return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); }

The issue is that we are conditionally calling the useEffect hook.

To solve the error, we have to move the condition inside of the hook because React hooks can only be called at the top level.

App.js
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); // ✅ hook is called at top level (not conditionally) useEffect(() => { if (counter > 0) { console.log('hello world'); } }); return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); }

We moved the if statement inside of the useEffect hook.

This solves the error because we have to ensure that React hooks are called in the same order each time a component renders.

This means that we aren't allowed to use hooks inside loops, conditions or nested functions.

Here is another example of how the error occurs.

App.js
import {useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); // 👇️ this returns before second hook runs if condition is met if (counter > 0) { return <h2>Returning early</h2>; } // ⛔️ Error because hook is called conditionally const [color, setColor] = useState('salmon'); return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); }

The issue is that the second useState hook is only invoked if the condition above it isn't met.

To solve the error, move all hooks at the top level of the component, above any conditions that might return a value.

App.js
import {useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); const [color, setColor] = useState('salmon'); // 👇️ condition that may return early must be below all hooks if (counter > 0) { return <h2>Returning early</h2>; } return ( <div> <button onClick={() => setCounter(counter + 1)}>toggle loading</button> <h1>Hello world</h1> </div> ); }

We moved the second useState hook below the if condition which could potentially return a value.

This helps because the hook is now at the top level and has predictable behavior that allows React to correctly preserve the state between useState and useEffect calls.

Like the documentation states:

  • Only call hooks at the top level
  • Don't call hooks inside loops, conditions or nested functions
  • Always use hooks at the top level of your React function, before any early returns
  • Only call hooks from React function components or custom hooks.

This helps React preserve the state of hooks between multiple useState and useEffect calls.

Conclusion #

The error "Rendered more hooks than during the previous render" occurs when we conditionally call a hook or return early before all hooks have ran. To solve the error, move all hooks at the top level of the function component and don't use hooks inside conditions.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.