MDN Fetch API - discussion (2022-12-17)
MDN is still the best baseline for fetch behavior (especially around cancellation and error handling). In React apps, though, the hard part is not calling fetch; it is making the fetch posture visible and consistent across routes.
How do you model cancellation and retries so it stays understandable in the UI? Do you treat abort as a local component detail, or as a route-level contract key that gets rendered as evidence? When fetch fails, what do you render so support can tell whether it was a network problem, a posture change, or a bad cache assumption?
Comments (10)
Back to latestI wish more teams treated abort as part of UX instead of a hidden implementation detail.
We started rendering a small fetch status marker in the route shell (pending, aborted, retrying).
It is not pretty, but it stops arguments about what the app is actually doing.
Related: Data Fetching and Caching Best Practices.
Minimal abort pattern that stayed readable for us:
ts
export async function fetchJson(url: string, signal?: AbortSignal) {
const res = await fetch(url, { signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
Then the UI can decide how to treat abort (ignored, surfaced, retried) instead of hiding it inside the helper.
Counterpoint: I do not like rendering too much fetch posture in UI.
It can leak implementation details to users and confuse them.
Same concern. We keep most of it behind an internal build flag and render it as data attributes, not user-facing text.
The goal is supportability: screenshots should carry enough evidence for triage.
The biggest fetch bug class for us was treating aborted as failed.
Once we separated those states, error rates dropped without changing the network behavior at all.
If you adopt render-fetch style, abort becomes even more important because rerenders can trigger new reads.
Making the abort posture explicit (even as a hidden lane) prevented a lot of duplicated in-flight work.
We had a misunderstanding internally: folks assumed fetch throws on 404 by default.
MDN being explicit about ok saved us from a lot of weird partial error handling.
We ended up with a tiny route-level rule: no retries without evidence. If a route retries, it must also render the retry count so you can see the behavior in screenshots and tests.
tsx
return <section data-retries={String(retries)} data-status={status}>...</section>;If you are streaming, I would also separate partial success from failure.
A lot of UIs treat it as all-or-nothing, but streams are naturally incremental.
MDN is a good reminder that the platform is the contract. React patterns sit on top of that reality.