import { useEffect, useState } from "react"; export interface FetchOpts { start?: () => void, end?: () => void, defaultValue?: T | (() => T), deps?: any[] | undefined, condition?: () => boolean, onSuccess?: (data: T) => void, onError?: (err: any) => void, } export function useFetch(fetcher: () => Promise, opts?: FetchOpts | any[] | undefined | null) { if (Array.isArray(opts)) { opts = { deps: opts }; } const options = (opts || {}) as FetchOpts; const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); const [data, setData] = useState(options.defaultValue); const fetch = () => { options.start && options.start(); setIsLoading(true); return fetcher().then((result: T) => { setData(result); options.onSuccess && options.onSuccess(result); }).catch(error => { setError(error); options.onError && options.onError(error); }).finally(() => { setIsLoading(false); options.end && options.end(); }); } useEffect(() => { if (!options.condition || options.condition()) { fetch(); } }, options.deps); return { data, isLoading, error, setData, refetch: fetch }; } export function useFetchOnce(fetcher: () => Promise, opts?: FetchOpts | any[] | undefined | null) { if (!opts || Array.isArray(opts)) { opts = { deps: [] }; } else if (opts) { opts.deps = []; } return useFetch(fetcher, opts); }