Skip to content

Instantly share code, notes, and snippets.

@web-crab
Created February 21, 2026 22:53
Show Gist options
  • Select an option

  • Save web-crab/f06231867c1589a12201bd0af4ac3c56 to your computer and use it in GitHub Desktop.

Select an option

Save web-crab/f06231867c1589a12201bd0af4ac3c56 to your computer and use it in GitHub Desktop.
import { useState, useRef, useCallback } from 'react';
function parseError(error: unknown): Error {
if (error instanceof Error) return error;
if (typeof error === 'string') return new Error(error);
return new Error('Unknown error');
}
export function useAsync<Data, Args extends unknown[]>(
fn: (...params: Args) => Promise<Data>,
) {
const [state, setState] = useState<{
data: Data | undefined;
error: Error | undefined;
isLoading: boolean;
}>({
data: undefined,
error: undefined,
isLoading: false,
});
const fnRef = useRef(fn);
const promiseRef = useRef<Promise<Data>>();
fnRef.current = fn;
const execute = useCallback((...args: Args) => {
const promise = fnRef.current(...args);
promiseRef.current = promise;
setState((prev) => ({ ...prev, isLoading: true }));
promise
.then((data) => {
if (promise === promiseRef.current) {
setState({ data, error: undefined, isLoading: false });
}
})
.catch((error) => {
if (promise === promiseRef.current) {
setState({
data: undefined,
error: parseError(error),
isLoading: false,
});
}
});
}, []);
return [state.data, state.isLoading, state.error, execute] as const;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment