AbortController for Effect Cleanup

AbortController provides a standard way to signal cancellation to supported asynchronous operations. In a UI effect, aborting during cleanup prevents obsolete work from continuing after the effect is replaced or the component is removed.

An `AbortController` creates an `AbortSignal` that asynchronous APIs can observe. You pass the signal to an operation such as `fetch`, then call `controller.abort()` when that work should no longer continue.

In React, this is useful inside `useEffect` when an async request belongs to the current effect instance. The cleanup function runs when the effect is removed or before React runs the effect again because its dependencies changed, so cleanup can abort the request associated with the previous instance.

Cancellation is cooperative: the controller does not magically terminate arbitrary JavaScript. The operation must support the signal, and application code should handle the resulting abort condition rather than treating every cancellation as a normal request failure.

Aborting obsolete requests also helps avoid stale results updating state after a newer request has become relevant. It is still important to structure the effect correctly because cancellation alone does not replace dependency management or other guards required by an application's async behavior.

Key points

Interview questions

Does AbortController cancel any promise?

No. AbortController is a signaling mechanism, not a universal promise-cancellation system. The asynchronous API must explicitly accept and respond to the `AbortSignal`. `fetch` supports this mechanism, while an arbitrary promise will continue unless its implementation cooperates with the signal.

Why would you use AbortController inside a React effect?

It lets an effect cancel supported asynchronous work when that effect is no longer relevant. For example, a `fetch` can receive an `AbortSignal`, and the cleanup function can call `abort()`. This is useful when a component unmounts or an effect reruns because a dependency changed. It reduces unnecessary work and helps prevent obsolete requests from affecting the UI.

What happens when an effect's dependency changes while its request is still running?

React cleans up the previous effect before running the replacement effect. If the cleanup calls `abort()`, the previous request receives the abort signal and a supported operation such as `fetch` rejects. The new effect then creates its own controller and starts its own request. This keeps cancellation scoped to the obsolete effect instance.

How should you distinguish an aborted request from a real network error?

The error from an aborted `fetch` is normally identified as an abort condition, commonly through `error.name === "AbortError"`. Application code can ignore or separately handle that expected condition while reporting genuine failures. The exact error representation can depend on the API, so code should follow the API's documented cancellation behavior. The key distinction is that user- or lifecycle-driven cancellation is not necessarily an application failure.

What are the limitations of using AbortController as an effect cleanup strategy?

AbortController only affects operations that honor its signal, so it is not sufficient for arbitrary asynchronous work. It also does not fix incorrect effect dependencies or guarantee that every asynchronous callback in an effect is harmless after cleanup. A robust design scopes resources to each effect execution and handles cancellation explicitly. For complex workflows, cancellation may need to propagate through multiple layers that all understand the signal.