Rules Hub
Coding Rules Library
Merge AbortSignals when bridging async contexts
Combine cancellation signals when using async libraries (like React Query) within framework lifecycles (like React Router) to ensure redundant requests are properly aborted.
Bad example
| 1 | export const loader = ({ request }: LoaderFunctionArgs) => { |
| 2 | return queryClient.fetchQuery({ |
| 3 | queryKey: ['user', params.id], |
| 4 | // Only uses React Query's signal, ignoring React Router's navigation cancellation |
| 5 | queryFn: ({ signal }) => fetch(`/api/user/${params.id}`, { signal }), |
| 6 | }); |
| 7 | }; |
Explanation (EN)
This code only respects the signal from the query library (React Query). If the user navigates away (triggering React Router's `request.signal`), the network request continues running unnecessarily because that signal is ignored.
Objašnjenje (HR)
Ovaj kod poštuje samo signal iz biblioteke za upite (React Query). Ako korisnik promijeni stranicu (što aktivira `request.signal` React Routera), mrežni zahtjev nastavlja raditi nepotrebno jer se taj signal ignorira.
Good example
| 1 | import { mergeAbortSignals } from '@/lib/utils'; |
| 2 |
|
| 3 | export const loader = ({ request }: LoaderFunctionArgs) => { |
| 4 | return queryClient.fetchQuery({ |
| 5 | queryKey: ['user', params.id], |
| 6 | queryFn: ({ signal: querySignal }) => { |
| 7 | // Combines navigation cancellation (request.signal) with query cancellation (querySignal) |
| 8 | const finalSignal = mergeAbortSignals(request.signal, querySignal); |
| 9 | return fetch(`/api/user/${params.id}`, { signal: finalSignal }); |
| 10 | }, |
| 11 | }); |
| 12 | }; |
Explanation (EN)
The signals are merged. The request now aborts if *either* the user navigates away (React Router) OR the query is cancelled internally (React Query, e.g., via timeout or unmount).
Objašnjenje (HR)
Signali su spojeni. Zahtjev se sada prekida ako korisnik promijeni stranicu (React Router) *ili* ako se upit interno otkaže (React Query, npr. zbog isteka vremena ili demontaže komponente).
Notes (EN)
Modern environments support `AbortSignal.any()`, but a polyfill or custom helper is needed for broader compatibility.
Bilješke (HR)
Moderna okruženja podržavaju `AbortSignal.any()`, ali za širu kompatibilnost potreban je polyfill ili vlastita pomoćna funkcija.