Prompt
Refactor duplicate code into a custom useFetch hook that takes a URL and returns { data, isLoading, error }.
Solution
Custom hooks are how React does DRY for stateful logic: the fetch-loading-error triad appears on every screen, and extracting it means the pattern is fixed in one place when it needs fixing. Which it does — the naive version everyone writes first has a race condition: if url changes (or the component unmounts) while a request is in flight, the old response lands last and overwrites the new one. The cancelled flag in the effect cleanup is the minimal fix; it's also the answer to the "can't perform a state update on an unmounted component" class of bug. In an interview, volunteering the race is worth more than the extraction itself.
Two more signals in the shape: [url] in the dependency array makes the hook re-fetch when its input changes — a hook that ignores its argument after mount is a stale-data bug; and returning a named object { data, isLoading, error } beats a tuple because call sites stay self-documenting.
The honest scope statement: this hook has no caching, deduplication, or retry. That's not a flaw in the exercise — it's why production apps use TanStack Query or SWR, which are this hook with the hard parts done.
Red flag: DRY-ing two snippets that are only coincidentally similar. Duplication is cheaper than the wrong abstraction — extract when the pattern has proven itself (rule of three), not on the second occurrence.
Say it: "I extract the triad into useFetch with a cancellation flag for the in-flight race — and I say out loud that caching and dedup are why the real version is TanStack Query."