Request on the first render
Short version: make the request in useEffect with an empty dependency array [] (only on the first mount), and remember cancellation and error handling. Here is a reliable template.
import { useEffect, useState, useRef } from "react";
export function UserOnce() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
// A guard against the effect running twice in Dev mode (StrictMode) in React 18
const didRunRef = useRef(false);
useEffect(() => {
if (didRunRef.current) return; // don't let it run a second time in Dev
didRunRef.current = true;
const controller = new AbortController();
(async () => {
try {
setLoading(true);
const res = await fetch("/api/user", { signal: controller.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
setData(json); // update state only if not cancelled
} catch (e) {
if (e.name !== "AbortError") setError(e);
} finally {
setLoading(false);
}
})();
// cleanup: cancel the request on unmount
return () => controller.abort();
}, []); // ← only the first render (mount)
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {String(error.message || error)}</p>;
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}Important points
-
Why
[]: the effect runs once - when the component mounts. -
StrictMode in Dev (React 18): effects can be called twice. The
useRefflag above prevents a duplicate request in development. In production the effect runs once. -
Cancelling the request:
AbortControlleris a must-have, so you don't catch asetStateon an unmounted component and don't waste the network. -
Where to get parameters: if the request depends on
props/state(for example,userId), include them in the dependencies:javascriptuseEffect(() => { // ...request with userId... }, [userId]);
and show loading when userId changes.
- Alternative: libraries like TanStack Query (React Query) and SWR take care of caching, cancellation, retries, stale-while-revalidate, and so on, simplifying the code.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.