Personal Catalogue: React, Express & MongoDB — Chapter 8, Exercise 3 ===================================================================== TASK Replace the naive hook with the fixed useDuplicateCheck (debounced, with the latestQuery staleness guard) and repeat the exact same typing sequence from Exercise 2, confirming the false warning no longer appears. SOLUTION export function useDuplicateCheck(title) { const [match, setMatch] = useState(null); const latestQuery = useRef(''); useEffect(() => { const trimmed = title.trim(); latestQuery.current = trimmed; if (trimmed.length < 3) { setMatch(null); return; } const timeoutId = setTimeout(async () => { const res = await fetch(`http://localhost:4000/api/items/search?q=${encodeURIComponent(trimmed)}`); const results = await res.json(); if (latestQuery.current !== trimmed) return; const exact = results.find((r) => r.title.toLowerCase() === trimmed.toLowerCase()); setMatch(exact || null); }, 400); return () => clearTimeout(timeoutId); }, [title]); return match; } Wired back into AddItemForm: const duplicateMatch = useDuplicateCheck(shared.title); Repeating the identical setup and typing sequence from Exercise 2 -- the same real "Dune" book already saved, typing "Dune Messiah" at the same continuous pace: Observed: while typing is still in progress, no request fires at all for most intermediate keystrokes -- the 400ms debounce means only a genuine pause triggers a real fetch call. If a request for a shorter, in-progress string (like "Dune") does happen to fire and then resolve late, the check `latestQuery.current !== trimmed` inside that callback catches it: by the time it runs, latestQuery.current already holds "Dune Messiah" (updated synchronously on every keystroke, regardless of the debounce), so the stale "Dune" match is discarded before setMatch() is ever called. Final state, once typing has fully stopped on "Dune Messiah": (no warning shown) The correct result -- no real duplicate exists for "Dune Messiah" -- and it stays correct regardless of which order any in-flight requests happen to resolve in. WHY THIS WORKS AS AN ANSWER ---------------------------- It swaps in the exact fixed hook the chapter provides, repeats the identical reproduction steps used to trigger the bug in Exercise 2, and confirms the specific false-positive result no longer occurs -- demonstrating the fix resolves the actual observed failure, not just a hypothetical one, using the same real scenario throughout.