Can you early return with React hooks?
React does not allow you to do an early return prior to other hooks. If a component executes fewer hooks than a previous render, you will get the following error:
Invariant Violation: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
React can't tell the difference between an early return before a hook call and a hook call that is conditional for some other reason. For instance, if you have 3 calls to useState
and you sometimes return after the second one, React can't tell whether you returned after the second useState
call or if you put a condition around the first or second useState
call, so it can't reliably know whether or not it is returning the correct state for the two useState
calls that did occur.
Here's an example that you can use to see this error in action (click the "Increment State 1" button twice to get the error):
import React from "react";
import ReactDOM from "react-dom";
function App() {
const [state1, setState1] = React.useState(1);
if (state1 === 3) {
return <div>State 1 is 3</div>;
}
const [state2, setState2] = React.useState(2);
return (
<div className="App">
<div>State 1: {state1}</div>
<div>State 2: {state2}</div>
<button onClick={() => setState1(state1 + 1)}>Increment State 1</button>
<button onClick={() => setState2(state2 + 1)}>Increment State 2</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
The alternative approach I would recommend is to separate the portion after the early return into its own component. Anything needed by the portion after the early return gets passed to the new component as props.
In the case of my example, it could look like the following:
import React from "react";
import ReactDOM from "react-dom";
const AfterEarlyReturn = ({ state1, setState1 }) => {
const [state2, setState2] = React.useState(2);
return (
<div className="App">
<div>State 1: {state1}</div>
<div>State 2: {state2}</div>
<button onClick={() => setState1(state1 + 1)}>Increment State 1</button>
<button onClick={() => setState2(state2 + 1)}>Increment State 2</button>
</div>
);
};
function App() {
const [state1, setState1] = React.useState(1);
if (state1 === 3) {
return <div>State 1 is 3</div>;
}
return <AfterEarlyReturn state1={state1} setState1={setState1} />;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);