Question presented to candidate: "Give me the full picture of doing async work inside an effect safely — every hazard you would guard against."
What a strong answer should cover:
- Why cleanup ordering is the foundation: it runs before the next effect, so a flag set there is guaranteed to beat the previous run's continuation.
- Race conditions: responses arriving out of order. A slow earlier request can overwrite a newer one, silently.
- Two guards, ranked:
AbortController(cancels the request and frees the connection) then a cancellation flag (only ignores the result). - Every await is a resumption point. The component may have unmounted or the dependency changed by the time each one resolves — so guard after each await, not only the first.
- The effect callback must not be
async— it would return a promise where React expects cleanup. - StrictMode runs setup, cleanup, setup, so an async effect must tolerate being started, aborted, and started again.
- Stale closures interact with this: an async continuation reads values captured at its own render.
- Swallow
AbortError, and never leave the error state unhandled. - The honest recommendation: this is a lot of invariants to maintain by hand, which is the argument for a query library.
Clarifying questions expected:
- "Is the work triggered by rendering, or by a user action?" — the latter belongs in a handler.
- "Can the underlying API be aborted, or only ignored?"
Code / implementation expected: Yes — a multi-await sequence with a guard after each step.