import { AxiosError } from 'axios'; import { useCallback, useEffect, useRef, useState } from 'react'; interface useApiOptions { queryFn: (...args: Args) => Promise; onComplete?: (data: NonNullable) => void; immediate?: boolean; } type ErrorType = { name: string; reason?: string; } | null; const useQuery = < T = Awaited>, Args extends any[] = [], >( options: useApiOptions, watch?: any[] ) => { const [response, setResponse] = useState(); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); const data = useRef(); const refetch = useCallback( async (...args: Args) => { setIsLoading(true); try { data.current = await options.queryFn(...args); setResponse(() => { setError(null); return data.current as T; }); options?.onComplete?.(data.current as NonNullable); } catch (error) { setError(() => { if (error instanceof AxiosError) { return { name: error.name, reason: error.message, }; } return { name: 'Network Error', }; }); } finally { setIsLoading(false); return data.current as T; } }, // eslint-disable-next-line react-hooks/exhaustive-deps [options.queryFn, options.onComplete] ); useEffect(() => { if (options.immediate === false) return; refetch(...([] as any)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [options.immediate, JSON.stringify(watch)]); return { refetch, isLoading, error, data: response as NonNullable, }; }; export default useQuery;