Rendered more hooks than during the previous render (React)

avatar
Borislav Hadzhiev

Last updated: Apr 6, 2024
6 min

banner

# Table of Contents

  1. Rendered more hooks than during the previous render
  2. Rendered fewer hooks than expected

# 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 run.

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

shell
Uncaught Error: Rendered more hooks than during the previous render. React has detected a change in the order of Hooks called by App. This will lead to bugs and errors if not fixed.

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. // React has detected a change in the order of Hooks // called by App. This will lead to bugs and errors if not fixed. 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.

Note: You might also get the error "React has detected a change in the order of Hooks called by X. This will lead to bugs and errors if not fixed".

The solution to the error is the same.

react has detected change in order of hooks

# Move the condition inside of the 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 the 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> ); }

move condition inside of hook

The code for this article is available on GitHub

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 the second hook runs if the 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 code for this article is available on GitHub

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

I've also written a detailed guide on solving the error React Hook 'useState' is called conditionally error.

# Move all hooks to the top level of the component

To solve the error, move all hooks to 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> ); }

move all hooks to top level of component

The code for this article is available on GitHub

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 a 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.

# Rendered fewer hooks than expected error in React

The error "Rendered fewer hooks than expected. This may be caused by an accidental early return statement" occurs when we use a hook after a conditional that may return a value.

To solve the error, move all React hooks above any conditionals that may return a value.

rendered fewer hooks than expected

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); // ๐Ÿ‘‡๏ธ may return a value before hook below runs if (counter > 0) { return <h1>Hello world</h1>; } // โ›”๏ธ Rendered fewer hooks than expected. // This may be caused by an accidental early return statement const [message, setMessage] = useState(''); return ( <div> <button onClick={() => setCounter(counter + 1)}>Increment count</button> </div> ); }
The code for this article is available on GitHub

The issue in the code sample is that we use the second useState hook after a condition that may return a value.

# Only call React hooks at the top level

To solve the error, we must only call React hooks at the top level.

App.js
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); // ๐Ÿ‘‡๏ธ move hooks above condition that might return const [message, setMessage] = useState(''); // ๐Ÿ‘‡๏ธ any conditions that might return must be below all hooks if (counter > 0) { return <h1>Hello world</h1>; } return ( <div> <button onClick={() => setCounter(counter + 1)}>Increment count</button> </div> ); }

only call react hooks at top level

We moved the second useState hook above the condition that might return a value.

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.

We have to make sure that all of the React hooks in a component are invoked in the same order on every render.

# Don't call React hooks conditionally

We should never call a hook conditionally.

App.js
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); if (counter > 0) { // โ›”๏ธ Error useEffect(() => { console.log('hello world'); }, []); } return ( <div> <button onClick={() => setCounter(counter + 1)}>Increment count</button> </div> ); }
The code for this article is available on GitHub

The code sample causes an error because the useEffect hook is called conditionally.

To get around this, we can move the if statement inside of the useEffect hook.

App.js
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); useEffect(() => { if (counter > 0) { console.log('hello world'); } }, [counter]); return ( <div> <button onClick={() => setCounter(counter + 1)}>Increment count</button> </div> ); }

place if statement inside useeffect hook

Moving the if statement inside of the hook 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 from custom hooks.

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

# Conclusion

The error "Rendered fewer hooks than expected. This may be caused by an accidental early return statement" means that we have rendered more hooks on the first render of a component than on a re-render.

This is caused by conditionally returning before a hook is used.

To solve the error, make sure to move your hooks to the top level of the component and place any conditionals that may return prematurely at the bottom.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

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.

Copyright ยฉ 2024 Borislav Hadzhiev