import { useEffect, useState } from 'react' import { SetState } from '../utils/types' import useSend from './useSend' type UseFetchShared = { loading: boolean, abort?: () => void, } type UseFetchSucced = { error: null, data: T, } & UseFetchShared type UseFetchErrored = { error: string, data: undefined } & UseFetchShared const gotError = (res: UseFetchErrored | UseFetchSucced): res is UseFetchErrored => ( typeof res.error === 'string' ) const fallbackError = (res: UseFetchSucced | UseFetchErrored) => ( gotError(res) ? res.error : res.data ) type UseFetchReturn = ({ error: null, data: T } | { error: string, data: undefined }) & { loading: boolean, setData: SetState abort?: (() => void) } function useFetch( url: string, method: RequestInit['method'], needAuth: boolean, guardResponse: (data: unknown) => data is R, processResponse: (data: R) => T, initialData?: T, params?: Omit ): UseFetchReturn { const [data, setData] = useState(initialData) const { doSend, loading, error } = useSend(url, method, needAuth, guardResponse, processResponse, params) useEffect(() => { doSend().then( data => { if (data !== undefined) setData(data) } ).catch( // must never occur err => import.meta.env.DEV && console.error('Failed to do fetch request', err) ) }, [doSend]) return { ...( error === null ? ({ data: data!, error: null }) : ({ data: undefined, error }) ), loading, setData } } export default useFetch export { gotError, fallbackError }