Detailed explanation
In a client-side React component, fetch data in an Effect rather than directly in the component’s render body. Rendering should remain pure: React can render a component multiple times, and starting requests during render can create duplicate requests and unpredictable updates. For a simple screen, use useEffect to start the request and useState to track data, loading, and error states. For shared server data or more complex applications, TanStack Query is often preferable because it manages caching, request coordination, retries, and status tracking.
With useEffect, create an AbortController inside the Effect and pass its signal to fetch. Define an async function inside the Effect, call it, and return a cleanup function that calls controller.abort(). Do not make the Effect callback itself async, because React expects it to return either nothing or a cleanup function, not a Promise. Before parsing JSON, check response.ok and throw an error for unsuccessful HTTP responses: fetch does not reject merely because the server returns 404 or 500. Set loading when starting, clear any previous error, and handle success and failure explicitly.
Cleanup runs before the Effect reruns with changed dependencies and when the component unmounts. Aborting prevents an obsolete request from continuing unnecessarily; ignore AbortError rather than showing it as a failure. Guard state updates with the signal’s aborted status when asynchronous processing can continue after cancellation, including updates in finally. Include every reactive value used by the Effect, such as userId, in its dependency array so the request stays synchronised with the component. An empty array is appropriate only when the Effect has no reactive dependencies. React Strict Mode also performs an extra setup-and-cleanup cycle in development, which exposes missing cleanup.
With TanStack Query, provide a query key describing the requested data and a query function that fetches it, checks HTTP status, and passes the supplied signal to fetch. Read data, error, and loading indicators from the query result. Include changing parameters in the key to keep cached results separate. Interviewers look for correct lifecycle handling, protection against stale responses, explicit error handling, and a reasoned choice between a small manual Effect and a server-state library.
Key points to remember
- For manual client-side fetching, use useEffect and track data, loading, and errors.
- Check response.ok before parsing; HTTP error statuses do not automatically reject fetch.
- Abort requests during cleanup and prevent cancelled work from updating state.
- Include reactive request parameters in Effect dependencies or query keys.
- Use TanStack Query for reusable server-state caching, retries, and request status management.
Common mistakes candidates make
- Starting fetch in the render body or declaring the useEffect callback async.
- Ignoring HTTP status checks, cleanup, or cancellation when updating loading and error states.
- Using an empty dependency array despite reading changing props, leading to stale data.
Likely follow-up questions
How do you prevent an older request from overwriting newer results?
Abort the previous request when dependencies change and guard subsequent state updates against cancellation. If the asynchronous API cannot be cancelled, use an Effect-local ignore flag set during cleanup or a request identifier to accept only the latest result.
Why can a request appear twice in development?
React Strict Mode performs an extra Effect setup-and-cleanup cycle in development to test cleanup behaviour. Correct cleanup aborts the first request, although it may already have reached the server.
Is useEffect always the best place to fetch data?
No; framework loaders or server-side data fetching can load data before the client component mounts and avoid client-side request waterfalls. For client-managed server state, TanStack Query offers caching and background refetching without manually rebuilding that logic.
Interview tip: Explain the Effect lifecycle first, describe HTTP error checks and cancellation, then explain when you would choose TanStack Query.
