React and UI state · 2 / 4
Fix stale search results
Your challenge
A search box requests results as the user types. The request for “re” finishes after the request for “react” and overwrites the screen. Fix this race without hiding errors.
Try it first. Write down your assumptions and explain your reasoning.
useEffect(() => {
const controller = new AbortController();
let active = true;
if (!query.trim()) { setResults([]); return; }
setLoading(true); setError('');
fetch(`/api/search?q=${encodeURIComponent(query)}`, {signal: controller.signal})
.then(r => { if (!r.ok) throw new Error('Search failed'); return r.json(); })
.then(data => { if (active) setResults(data); })
.catch(e => { if (active && e.name !== 'AbortError') setError(e.message); })
.finally(() => { if (active) setLoading(false); });
return () => { active = false; controller.abort(); };
}, [query]);1.Separate input from request state
Keep the current query, results, loading state and error state distinct. A debounce reduces request volume, but it cannot guarantee response order. Clear a stale error when a new request starts and preserve useful old results while refreshing if the UI communicates that state.
2.Cancel and guard obsolete requests
Create an AbortController per request and abort it during effect cleanup. Also use a monotonically increasing request number or an active flag so an obsolete response cannot commit state. The guard covers non-abortable work and responses that already reached the application.
3.Handle empty input and failures
When the query becomes empty, abort outstanding work and reset the search view. Treat AbortError as expected cancellation; other errors need an actionable message. Include the query in the effect dependency list and avoid sharing one controller across requests.
Take it one step further
- 1.Does debouncing alone prevent this race?
- 2.How would a query cache affect repeated searches?
Self-review
Can you explain each point without looking at the solution?
- Prevent obsolete state updates
- Distinguish cancellation from errors
- Discuss empty input and cleanup
