Skip to content

Clean up React async work

Prerequisites

Run the complete React example first. Its slow fixture gives you 2000 ms to cancel and its play check waits beyond that duration to detect late results. For a custom Promise, the operation must accept the controller; state protection alone cannot stop external work.

Give the hook the real cancellation path

useFetcher supplies its owned controller to the Fetcher request. If you instead use useExecutePromise, forward the supplied signal yourself:

tsx
const work = useExecutePromise<string>();
const load = () =>
  work.execute(async controller => {
    const response = await fetch('/api/message', { signal: controller.signal });
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return response.text();
  });

Import useExecutePromise from @ahoo-wang/fetcher-react and put these lines inside your component. Bind load to Load, work.abort to Cancel, and render work.loading, work.error, and work.result as in the complete request component. This alternative requires GET /api/message returning plain text; the repository fixture does not provide it.

Use the correct cleanup action

ActionWhat it doesUse it for
abort()Invalidates and aborts the active execution, returning to idleStop or cancel an active operation
reset()Sets state to idle without invalidating/aborting active workClear a settled presentation state
Debounced hook cancel()Removes pending schedulingPrevent a queued invocation
Component unmountCleans up hook-owned execution and debounce timersEnd the component's work

A new execution aborts its predecessor; the request sequence and mounted check suppress stale state updates. A custom promise that ignores its controller may still finish externally. A Stop button for a debounced request needs both cancel and abort. Use a fresh execution/controller for another attempt.

Verify cancellation rather than just a cleared screen

Start the slow example, cancel it, then wait longer than 2000 ms: it should stay idle. Repeat by unmounting the component before completion and checking the replacement screen stays unchanged. A call to reset during an active request is not an equivalent test, because that request may subsequently publish success.

Catch operation failures at the state or promise boundary according to propagateError. Native AbortError cancellation returns to idle; do not invent a successful data result for it. Clear any timers and external listeners you created outside the hook separately. SSR identity and shared-client isolation remain application responsibilities.

See promise lifecycle, HTTP cancellation, and state and resources.

Released under the Apache License 2.0.