We use cookies for site analytics. Accept to help us understand how the site is used. See our Privacy Policy for details.
A medium frontend problem, graded against 4 test cases (2 of them hidden).
React and browser-platform problems - hooks, event handling, and rendering behaviour.
Reach for it when you see: A component, hook, or DOM-behaviour question rather than an algorithm.
More Frontendproblems →```tsx
type State<T> = {
data: T | null;
error: Error | null;
status: "idle" | "loading" | "success" | "error";
};
type Action<T> =
| { type: "start" }
| { type: "success"; payload: T }
| { type: "error"; error: Error };
function fetchReducer<T>(state: State<T>, action: Action<T>): State<T> {
switch (action.type) {
case "start": return { ...state, status: "loading", error: null };
case "success": return { data: action.payload, error: null, status: "success" };
case "error": return { ...state, error: action.error, status: "error" };
}
}
export function useFetch<T>(url: string) {
const [state, dispatch] = useReducer(fetchReducer<T>, { data: null, error: null, status: "idle" });
useEffect(() => {
const ctl = new AbortController();
dispatch({ type: "start" });
fetch(url, { signal: ctl.signal })
.then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json() as Promise<T>; })
.then(payload => dispatch({ type: "success", payload }))
.catch(error => {
if ((error as Error).name === "AbortError") return;
dispatch({ type: "error", error: error as Error });
});
return () => ctl.abort();
}, [url]);
return state;
}
```
Why useReducer over multiple useStates: state transitions are atomic. With three separate `useState` calls (`data`, `error`, `status`) it's easy to forget to clear `error` when refetching, leaving a stale error onscreen. A reducer makes invalid states unreachable.
Production-grade alternatives: in real apps, prefer SWR / TanStack Query / RTK Query - they handle dedup, caching, retry, refocus-revalidation, and more. Implement `useFetch` from scratch only for interview problems or simple cases.
The full reference solution in every supported language stays in the editor above - reveal it there once you have had a real attempt.
These apply to the pattern as a whole, not just this problem.