Why this matters
The bug. Each query change spawns a new fetch, but old fetches don't get cancelled. Network ordering is non-deterministic — the slow earlier request can land *after* the fast later one and clobber the correct results.
The fix. Use the effect cleanup to ignore stale responses (or, modern: pass an AbortSignal and abort on cleanup):
useEffect(() => {
let cancelled = false;
fetch(...).then(data => { if (!cancelled) setResults(data) });
return () => { cancelled = true };
}, [query]);
Pattern. Any time you setState from an async result inside an effect, ask: what if this is stale?
Review heuristic
Every check-then-act over shared state is a race waiting for production load. Look for read-then-write pairs that aren't inside a transaction, a lock, or an atomic CAS. If you can articulate the bug as "if two requests arrive at the same time, both will...", it's a race.
External reference: CWE-362: Concurrent Execution using Shared Resource.