dh_demo

DreamHanks demo project
git clone git://git.lair.cx/dh_demo
Log | Files | Refs | README

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 }