State

state/fetch-effect-cleanup

An effect that fetches into state returns a cleanup that ignores or aborts stale responses.

moderatestaticfe-data-fetching

Why

When the input changes quickly (typing in a search box, clicking through pages), several requests are in flight and their answers arrive in any order. Without a cleanup, the last answer to arrive wins, so the page can show results for "hel" under the query "hello". A response that lands after the component unmounted also writes into a dead component.

Fix

Return a cleanup: let ignore = false … if (!ignore) setResults(json) … return () => { ignore = true }, or pass an AbortController signal to fetch and call abort() in the cleanup. Better still, load page data with the framework (Server Components, route loaders) or a server-state library (TanStack Query, SWR), which handle races, caching and deduplication.

Examples

// bad
useEffect(() => {
  fetch(`/api/search?q=${query}`).then((r) => r.json()).then(setResults)
}, [query])
// good
useEffect(() => {
  const controller = new AbortController()
  getJson(`/api/search?q=${query}`, { signal: controller.signal }).then(setResults, onError)
  return () => controller.abort()
}, [query])

Sources

Facts

Id
state/fetch-effect-cleanup
Severity
moderate
Check
static checked in the source by audit
Applies to
jsx
Only in projects with
react next preact
Taught by the skill
fe-data-fetching Data fetching
Since version
0.1.0

Rule file on GitHub

Read it in the terminal

npx github:dawidolko/frontend-skills explain state/fetch-effect-cleanup