Networks fail. A good UI doesn't just show "Something went wrong" — it shows a Retry button that re-runs the exact same request, not a blank one. useAsyncRetry builds that: it runs an async function, tracks the usual status/value/error, and exposes a retry() that replays the last call with the same arguments, plus an attempts counter for backoff or "tried 3 times" messaging.
Implement useAsyncRetry(asyncFunction, immediate = true). It returns { status, value, error, attempts, run, retry }. run(...args) executes and remembers its arguments; retry() re-runs with those same arguments. Every run and retry bumps attempts.
function useAsyncRetry(asyncFunction, immediate = true) {
// returns { status, value, error, attempts, run, retry }
}
const { status, error, retry, attempts } = useAsyncRetry(() => loadFeed());
if (status === 'error') {
return <button onClick={retry}>Retry (attempt {attempts + 1})</button>;
}
const { run, retry } = useAsyncRetry(searchUsers, false);
run('ada'); // searches "ada"
retry(); // re-runs searchUsers('ada'), NOT searchUsers()
retry replays the exact call, even after re-renders (a closure would go stale).pending, like a fresh run.run and retry; handy for capped retries or backoff.run/retry — memoize both so they're safe as effect deps and button handlers.