Hooks and effects
Follow the Rules of Hooks
Call Hooks at the top level of React components and custom Hooks so the call order stays stable between renders.
Call Hooks at the top level of a React component or custom Hook.
Do not call a Hook inside a condition:
if (isLoggedIn) {
const [profile, setProfile] = useState(null)
}
React matches Hook state by call order. If one render calls the Hook and the next skips it, every later Hook can be matched with the wrong stored value.
Call the Hook unconditionally, then branch with the result:
const [profile, setProfile] = useState(null)
if (!isLoggedIn) {
return <Login />
}
Do not call Hooks in loops, nested callbacks, event handlers, or after an early return. Call them only while React is rendering a component or another Hook.
Put a condition inside an Effect when the synchronization itself is conditional. Split the component when two branches genuinely need different stateful structures.
Some data Hooks accept a value that pauses their work. You still call the Hook on every render, but move the condition into its argument. SWR, for example, skips a request when its key is null:
const { data } = useSWR(isLoggedIn ? '/api/user' : null, fetcher)
Use the React Hooks linter. It can catch invalid call positions and missing Effect dependencies before they become timing bugs.
Move one Hook below an early return and run the linter. Then restore it to the top level and explain why the order is stable again.
Lesson completed