Stop Calling useContext Directly in Your Components
A codebase that calls `useContext` directly in dozens of components resists change. Switching a data source or adding cross-cutting logic forces edits across the entire component tree. The custom Hook pattern turns that into a single-file change, which is the difference between a quick fix and a regression-prone refactor.
Direct `useContext` calls scatter imports and implementation details across every consuming component. When requirements change — a fallback to localStorage, an analytics event on value change, or a switch to a different state management library — every file must be touched. Moving that single `useContext` call into a custom Hook like `useTheme` or `useMouse` makes the data source an internal detail. Components import one function and call it; they never see the Context object or even the `useContext` import.
The payoff is immediate: fewer imports per file, a single place to add middleware logic, and drastically simpler unit tests that mock one Hook instead of wrapping components in Provider trees. The pattern generalizes beyond Context. Any React logic combining state and effects — mouse tracking, form handling, WebSocket subscriptions — benefits from the same encapsulation.
React's own documentation treats Context-wrapping Hooks as the canonical entry point for custom Hooks because the change is minimal and the maintainability win is large. The rule is mechanical: create a Context, immediately write a `use[Name]` Hook, and forbid direct `useContext` calls everywhere else.
The argument is not about correctness — both patterns produce identical runtime behavior — but about where the knowledge of 'how to get this data' lives. Spreading that knowledge across components is a maintenance tax that compounds with every new consumer.
React's own API design nudges developers toward the direct pattern because `useContext` is the primitive shown in tutorials. The custom Hook pattern is a social convention that corrects a structural weakness in the primitive's ergonomics.
The same logic that makes Context-wrapping Hooks valuable applies to any cross-cutting concern: a single `useAnalytics` Hook that wraps Context is easier to change than analytics calls scattered across components, even if both approaches 'work' today.