Borislav Hadzhiev
Tue Apr 05 2022·3 min read
Photo by John Purakal
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.
Here is an example of how the error occurs.
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 issue in the code snippet is - we use the second useState
hook after a
condition that may return a value.
To solve the error, we must only call React hooks at the top level.
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> ); }
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 should never call a hook conditionally.
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); if (counter > 0) { // ⛔️ Error - useEffect is called conditionally useEffect(() => { console.log('hello world'); }, []); } return ( <div> <button onClick={() => setCounter(counter + 1)}>Increment count</button> </div> ); }
The code snippet in the example 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.
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> ); }
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:
This helps React preserve the state of hooks between multiple useState
and
useEffect
calls.
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 at the top level of the component and place any conditionals that may return prematurely at the bottom.