Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Cancel in-flight requests with AbortController
Abort old requests on unmount or param changes to prevent race conditions and wasted work.
Bad example
| 1 | import { useEffect, useState } from "react"; |
| 2 |
|
| 3 | export function SearchResults({ query }: { query: string }) { |
| 4 | const [results, setResults] = useState<string[]>([]); |
| 5 |
|
| 6 | useEffect(function fetchResults() { |
| 7 | fetch(`/api/search?q=${encodeURIComponent(query)}`) |
| 8 | .then((r) => r.json()) |
| 9 | .then((data) => setResults(data.items)); |
| 10 | }, [query]); |
| 11 |
|
| 12 | return <pre>{JSON.stringify(results, null, 2)}</pre>; |
| 13 | } |
Explanation (EN)
Fast query changes can cause responses to resolve out of order. Older responses may overwrite newer results, and network work continues after the component is no longer relevant.
Objašnjenje (HR)
Brze promjene queryja mogu dovesti do toga da se odgovori vrate van redoslijeda. Stariji odgovor moze prepisati novije rezultate, a mrežni rad se nastavlja i nakon sto komponenta vise nije relevantna.
Good example
| 1 | import { useEffect, useState } from "react"; |
| 2 |
|
| 3 | export function SearchResults({ query }: { query: string }) { |
| 4 | const [results, setResults] = useState<string[]>([]); |
| 5 |
|
| 6 | useEffect(function fetchResults() { |
| 7 | const ctrl = new AbortController(); |
| 8 |
|
| 9 | fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal: ctrl.signal }) |
| 10 | .then((r) => r.json()) |
| 11 | .then((data) => setResults(data.items)) |
| 12 | .catch((err: unknown) => { |
| 13 | if (err instanceof DOMException && err.name === "AbortError") return; |
| 14 | throw err; |
| 15 | }); |
| 16 |
|
| 17 | return () => { |
| 18 | ctrl.abort(); |
| 19 | }; |
| 20 | }, [query]); |
| 21 |
|
| 22 | return <pre>{JSON.stringify(results, null, 2)}</pre>; |
| 23 | } |
Explanation (EN)
AbortController cancels the previous request when the query changes or the component unmounts. This prevents stale updates and reduces wasted network work.
Objašnjenje (HR)
AbortController prekida prethodni request kada se query promijeni ili se komponenta unmounta. Time se sprijecavaju stale updateovi i smanjuje nepotreban mrežni rad.
Notes (EN)
If you also have timeouts or parent signals, merge signals (e.g., AbortSignal.any) and still handle AbortError explicitly.
Bilješke (HR)
Ako imas timeoute ili parent signale, spoji signale (npr. AbortSignal.any) i i dalje eksplicitno handle-aj AbortError.
Exceptions / Tradeoffs (EN)
Do not abort fire-and-forget requests that must complete (e.g., audit logs). Decouple them from UI state instead.
Iznimke / Tradeoffi (HR)
Nemoj abortati fire-and-forget requestove koji moraju zavrsiti (npr. audit logovi). Odvoji ih od UI state-a.