use_api.ts (1231B)
1 import { useCallback, useState } from 'react' 2 3 export interface UseApiOptions<TBody> extends Omit<RequestInit, 'body'> { 4 body?: (() => TBody) | TBody 5 } 6 7 export default function useApi<T, TBody extends object> ( 8 req: RequestInfo | URL, 9 opt?: UseApiOptions<TBody>, 10 ): [T | null, boolean, number, () => void] { 11 const [isLoading, setLoading] = useState(false) 12 const [statusCode, setStatusCode] = useState(0) 13 const [data, setData] = useState<T | null>(null) 14 15 const { body, ...options } = opt ?? {} 16 17 const doFetch = useCallback(async () => { 18 setLoading(true) 19 20 const init: RequestInit = { 21 ...options, 22 } 23 24 if (body != null) { 25 init.body = JSON.stringify( 26 typeof body === 'function' 27 ? body() 28 : body, 29 ) 30 } 31 32 if (init.body != null) { 33 init.headers = { 34 'Content-Type': 'application/json', 35 ...init.headers, 36 } 37 } 38 39 const resp = await fetch(req, init) 40 41 setStatusCode(resp.status) 42 setData(await resp.json()) 43 44 setLoading(false) 45 }, [opt, req]) 46 47 const trigger = useCallback(() => { 48 doFetch() 49 .catch((err) => console.error('api error:', err)) 50 }, [doFetch]) 51 52 return [data, isLoading, statusCode, trigger] 53 }