Question presented to candidate: "Walk me through doing async work in a function component — and the bugs that come with it."
What a strong answer should cover:
- Never make the effect callback itself
async. It returns a promise where React expects a cleanup function, and React warns about it explicitly. - The correct shape: define an async function inside the effect and call it, then return a real cleanup.
- Race conditions are the headline bug: responses can arrive out of order, so a slow earlier request can overwrite a newer one.
- Two fixes: a cancellation flag (ignore the stale result) or
AbortController(actually cancel the request). Prefer the latter — it frees the connection too. - Handle all three states — loading, error, success — and remember an aborted request rejects with an
AbortErroryou should not surface as a failure. - Event handlers can be
asyncfreely; only the effect callback has the return-value constraint. - React 19:
use()with Suspense for reading a promise, anduseActionState/useTransitionfor async form submissions. - The honest recommendation: for server data, use a library — it solves caching, deduplication, and staleness, not just ordering.
Clarifying questions expected:
- "Is this triggered by rendering, or by a user action?" — effect versus handler.
- "Can we use a data library, or does this need to be hand-rolled?"
Code / implementation expected: Yes — the AbortController effect, and the race condition it prevents.