Drills Repository
20 Drills · All Belts · rules-of-hooks
Hook naming and lint behavior
React's Rules of Hooks rely on the "use" naming convention to identify valid Hook call locations, since the linter treats any function starting with "use" as a Hook. Renaming the function removes that signal, so calls inside it are flagged as invalid Hook usage.
Hooks inside event handlers
Hooks are tied to React's render cycle and must execute while React is actively rendering a function component or custom Hook. Event handlers run later in response to user interaction, outside the render process, so React cannot correctly track Hook state there.
Custom Hooks calling Hooks
Custom Hooks work because they remain part of React's rendering flow and must obey the same Rules of Hooks as components. React does not grant them special behavior based on compilation or naming alone; the "use" prefix is simply a linter convention.
Conditionally Calling getSorted Inside a Component
The Rules of Hooks require Hooks to be called unconditionally and in the same order every render, but that requirement applies only to functions that actually call Hooks. Since getSorted only sorts an array and never calls a Hook, calling it inside an if block does not violate hook ordering.
Hook naming affects lint behavior
React's linter identifies Hooks purely by the use naming convention, since it has no other way to know which functions call Hooks internally. Renaming useOnlineStatus to getOnlineStatus removes that signal, so the linter can no longer verify the useState and useEffect calls inside it follow the rules.
Non-Hook utilities can be conditional
React tracks Hook call order only for functions that themselves call Hooks, so plain utility functions are invisible to that tracking and safe to call conditionally. getSorted contains no Hook calls and can run conditionally, but useSorted must execute in the same order on every render because it calls Hooks internally.
useRef inside loops
Hooks rely on identical call order across every render to correctly match internal state slots. Calling useRef inside a map means the number of Hook calls varies with the list's size, which breaks React's Hook tracking system and is why Hooks must remain at a component's top level.
Hooks in regular functions
Hooks may only run inside React function components or custom Hooks because React depends on controlled render execution to associate Hook state correctly. Here, setOnlineStatus is a plain function rather than a component or custom Hook, so calling useOnlineStatus inside it falls outside React's render tree.
A useState Hook Guarded by a Flag
React matches Hook state internally by call order across renders, not by variable name. When a Hook is skipped due to a condition, the call order shifts, and React associates the wrong internal state with subsequent Hooks.
Hook after conditional return
Hooks must execute in the exact same order on every render for React to correctly match state and effects. A conditional return placed before a Hook call can prevent that Hook from running on some renders, shifting the ordering React relies on.
Hooks inside useMemo callback
React only permits Hook calls at the top level of a component or custom Hook, where render order can be tracked consistently across renders. The callback passed to useMemo is a nested function rather than a component or Hook render scope, so calling useContext() inside it is invalid.
Calling useMemo Inside a .map() Callback
React requires hooks to be called in the exact same order and quantity on every render of a component, and a .map() loop whose iteration count varies breaks that invariant. The fix for ItemList is to hoist a single useMemo above the loop that memoizes the whole formatted array, or to move the per-item logic into its own child component.