Capítulo 41 de 116

Chapter 41: Reusing Logic with Custom Hooks

Core Idea

A custom Hook is just a JavaScript function whose name starts with use and that calls other Hooks inside it — it lets stateful logic (not just the resulting JSX) be extracted and reused across components, which neither a regular function nor a wrapper component can do on its own.

Key Concepts

  • Why not just a regular function? A plain helper function can share calculations, but not stateful behavior — it can't call useState/useEffect itself and have that state live inside the calling component the way a custom Hook can.
  • Naming and rules: must start with use; internally calls other Hooks (built-in or custom), and therefore must itself follow the Rules of Hooks (Ch 116) — called only at the top level, not inside conditions/loops.
  • What gets shared is the logic, not the state itself. Two components each calling the same custom Hook (useOnlineStatus()) get two fully independent instances of that Hook's internal state — exactly like two calls to useState in two different components never share a value. The Hook shares behavior, not a value.
  • Passing reactive values between Hooks: a custom Hook can accept parameters and return values just like a regular function, and those parameters flow into the Hooks it calls internally — e.g. a useChatRoom({ serverUrl, roomId }) custom Hook wraps a useEffect whose dependency array includes serverUrl/roomId, so the parameters passed to the custom Hook drive the Effect the same way they would if written inline.
  • When to extract a custom Hook: when the same stateful logic (not just markup) is duplicated across multiple components, or when isolating a piece of synchronization logic makes a component's own code substantially more readable — even for logic used only once, if it clarifies intent (a useChatRoom name documents "this manages a chat connection" better than an inline Effect does).
  • Custom Hooks let implementation details change without touching call sites — swapping an underlying browser API a Hook wraps (e.g. how "online status" is detected) only requires editing the Hook's internals; every component using useOnlineStatus() is unaffected.

Code Examples

function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);
  useEffect(() => {
    function update() { setIsOnline(navigator.onLine); }
    window.addEventListener('online', update);
    window.addEventListener('offline', update);
    return () => {
      window.removeEventListener('online', update);
      window.removeEventListener('offline', update);
    };
  }, []);
  return isOnline;
}
  • What it demonstrates: a complete custom Hook — internally uses useState + useEffect, exposes a single derived value, reusable by any component as const isOnline = useOnlineStatus();.

Key Takeaways

  1. Custom Hooks share reusable stateful logic; each call site still gets its own independent state — never assume two components using the same custom Hook are somehow "connected."
  2. Extracting a custom Hook is often worth it purely for naming/readability, even without duplication — a well-named Hook documents what an Effect is for.
  3. Because a custom Hook is "just a function that calls Hooks," everything from earlier chapters (dependency arrays, Effect Events, purity) still applies inside it exactly as it would inline.

Connects To

  • Ch 36 (Synchronizing with Effects): the Effect logic most custom Hooks in this style wrap.
  • Ch 116 (Rules of Hooks): the rules a custom Hook must follow, same as any built-in Hook usage.
  • Ch 12 (Importing and Exporting Components): the same export/import mechanics apply to a custom Hook's own file.