useAsync Hook
A custom React Hook for handling async operations with loading/error states (TypeScript)
Code
import { useState, useCallback, useRef, useEffect } from 'react';
type AsyncState<T> = {
data: T | null;
loading: boolean;
error: Error | null;
};
type AsyncOptions = {
autoExecute?: boolean;
onSuccess?: (data: any) => void;
onError?: (error: Error) => void;
};
function useAsync<T>(
asyncFunction: (...args: any[]) => Promise<T>,
options: AsyncOptions = {}
): {
state: AsyncState<T>;
execute: (...args: any[]) => Promise<T | null>;
reset: () => void;
} {
const { autoExecute = true, onSuccess, onError } = options;
const [state, setState] = useState<AsyncState<T>>({
data: null,
loading: false,
error: null,
});
const isMountedRef = useRef(true);
// Cleanup on unmount
useEffect(() => {
__TOKEN_15__ () => {
isMountedRef.current = false;
};
}, []);
const execute = useCallback(__TOKEN_17__ (...args: any[]) => {
__TOKEN_18__ (!isMountedRef.current) return null;
setState(prev => ({ ...prev, loading: true, error: null }));
try {
const data = await asyncFunction(...args);
__TOKEN_23__ (!isMountedRef.current) return null;
setState({ data, loading: false, error: null });
onSuccess?.(data);
return data;
} __TOKEN_26__ (error) {
__TOKEN_27__ (!isMountedRef.current) return null;
const err = error as Error;
setState({ data: null, loading: false, error: err });
onError?.(err);
return null;
}
}, [asyncFunction, onSuccess, onError]);
const reset = useCallback(() => {
setState({ data: null, loading: false, error: null });
}, []);
// Auto execute on mount
useEffect(() => {
__TOKEN_32__ (autoExecute) {
execute();
}
}, [execute, autoExecute]);
return { state, execute, reset };
}
// Usage example
// const fetchUser = (id: number) => fetch(`/api/users/${id}`).then(res => res.json());
// const { state: { data: user, loading, error }, execute: fetchUserById } = useAsync(fetchUser, { autoExecute: false });
// <button onClick={() => fetchUserById(1)}>Load User</button>