█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/React (Standalone Deep Dive)/Hooks in Depth
55 minIntermediate

Hooks in Depth

After this lesson, you will be able to: Use every common hook correctly: useState, useEffect, useContext, useReducer, useRef, useMemo, useCallback, useTransition, useDeferredValue.

Hooks are simple by themselves; combinations + dependency arrays are where bugs live.

Prerequisites:React Rendering Model

useState + useEffect

The basics; get them right.

tsx
const [count, setCount] = useState(0);
// Effect, synchronizes with external systems
useEffect(() => {
document.title = `Count: ${count}`;
return () => { document.title = "App"; }; // cleanup
}, [count]);
// Dependency array tells React WHEN to re-run.
// [] = once on mount.
// no array = every render (almost never what you want).
// [count] = whenever count changes.

useMemo + useCallback (use sparingly)

Cache expensive computations + stable function refs.

tsx
// Cache the result of an expensive sort
const sorted = useMemo(() => items.sort((a, b) => a.x - b.x), [items]);
// Stable callback reference (matters for child memoization or effect deps)
const handleClick = useCallback((id: string) => setSelected(id), []);
// Don't wrap everything in useMemo/useCallback. They have their own cost. Use when:
// - Computation is genuinely slow (>5ms)
// - You pass a function/object as a prop to a memoized child
// - You depend on the ref in another hook's deps

useReducer (when useState gets messy)

State machine pattern.

tsx
type State = { count: number; user: User | null };
type Action = { type: "inc" } | { type: "set-user"; user: User };
function reducer(s: State, a: Action): State {
switch (a.type) {
case "inc": return { ...s, count: s.count + 1 };
case "set-user": return { ...s, user: a.user };
}
}
const [state, dispatch] = useReducer(reducer, { count: 0, user: null });
dispatch({ type: "inc" });

useTransition + useDeferredValue (concurrent)

Mark updates as low-priority.

tsx
const [isPending, startTransition] = useTransition();
const [query, setQuery] = useState("");
function onInput(e) {
// Update input immediately (urgent)
// Mark expensive list-filter as transition (interruptible)
startTransition(() => setQuery(e.target.value));
}
// In the consumer: useDeferredValue
const deferredQuery = useDeferredValue(query);
// Heavy filter uses deferredQuery; recent input keeps UI responsive.

Common mistakes only experienced React devs avoid

Missing dependencies in useEffect. ESLint's `react-hooks/exhaustive-deps` rule is your friend; don't disable. useMemo/useCallback on every prop. Pure overhead unless there's a concrete reason. Conditional hook calls. Hooks must run in the same order every render. Setting state in an effect that depends on that state. Infinite render loop.

Quick Check

Why is `useEffect(() => setX(y), [y])` an infinite loop sometimes?

Pick the senior answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←React Rendering Model
Back to React (Standalone Deep Dive)
Custom Hooks→