React Hooks Deep Dive
If an interviewer asks you about hooks and you start with useState, you're thinking too small. Senior engineers discuss hooks as a paradigm for composing stateful logic.
How Hooks Work Internally
React maintains a linked list of hooks for each component instance. Each call to a hook corresponds to a node in this list, in order.
This is why hooks have rules:
- Don't call hooks conditionally â the list would get out of order
- Don't call hooks in loops â same reason
- Call hooks at the top level â React relies on call order being stable
Component renders â Hook 1 â Hook 2 â Hook 3
useState useEffect useMemoIf you add a conditional hook between renders, Hook 2 might read Hook 3's data. Everything breaks silently.
useEffect is Not componentDidMount
The mental model shift:
- Class lifecycle: "Run this code when the component mounts/updates/unmounts"
- Hooks: "Synchronize this side effect with these dependencies"
// Wrong mental model
useEffect(() => {
fetchUser(id); // "Fetch when id changes"
}, [id]);
// Right mental model
useEffect(() => {
// Keep this effect synchronized with `id`
let cancelled = false;
fetchUser(id).then(data => {
if (!cancelled) setUser(data);
});
return () => { cancelled = true; };
}, [id]);The cleanup function isn't "componentWillUnmount" â it runs before every re-execution of the effect.
Custom Hooks â The Real Power
Custom hooks are the primary abstraction for sharing stateful logic:
function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(false);
useEffect(() => {
const mql = window.matchMedia(query);
setMatches(mql.matches);
const handler = (e: MediaQueryListEvent) => setMatches(e.matches);
mql.addEventListener('change', handler);
return () => mql.removeEventListener('change', handler);
}, [query]);
return matches;
}
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
try {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
} catch {
return initialValue;
}
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}The Hook Composition Pattern
Senior pattern: compose hooks from smaller hooks.
function useAuth() {
const [user, setUser] = useLocalStorage('user', null);
const isDesktop = useMediaQuery('(min-width: 1024px)');
const login = useCallback(async (credentials) => {
const user = await authAPI.login(credentials);
setUser(user);
}, [setUser]);
const logout = useCallback(() => {
setUser(null);
}, [setUser]);
return { user, login, logout, isDesktop };
}Interview Signal
When discussing hooks, demonstrate:
- Internal understanding â linked list, call order invariant
- Correct mental models â synchronization, not lifecycle
- Composition â custom hooks as the abstraction boundary
- Pitfall awareness â stale closures, missing deps, race conditions