REACT

useAsync Hook

A custom React Hook for handling async operations with loading/error states (TypeScript)

ReactHooksAsyncPromisesAPI

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>