import { useCallback, useEffect, useState } from 'react' type UrlInput = Parameters[0] type Overrides = { fetch?: typeof fetch onError?: (arg: unknown) => void } export const useRequest = (url: UrlInput, overrides?: Overrides) => { const usedFetch = overrides?.fetch ?? fetch const usedLogger = overrides?.onError ?? console.error.bind(console) const [isLoading, setIsLoading] = useState(false) const [data, setData] = useState(undefined) const refresh = (target: UrlInput, abortSignal?: AbortSignal) => { setIsLoading(true) usedFetch(target, { signal: abortSignal, }) .then((response) => response.json()) .then((incomingData) => setData(incomingData)) .catch((err) => { usedLogger(err) setData(undefined) }) .finally(() => setIsLoading(false)) } useEffect(() => { const controller = new AbortController() refresh(url, controller.signal) return () => controller.abort() }, [url.toString()]) const refetch = useCallback(() => { refresh(url) }, [url]) return { refresh: refetch, isLoading, data } }