{"version":3,"file":"useFetch-48821fc2.js","sources":["../../../../src/scripts/hooks/useFetch.tsx"],"sourcesContent":["import { useEffect, useReducer, useRef } from 'react';\n\ninterface State<T> {\n  data?: T;\n  error?: Error;\n}\n\ntype Cache<T> = { [url: string]: T };\n\n// discriminated union type\ntype Action<T> =\n  | { type: 'loading' }\n  | { type: 'fetched'; payload: T }\n  | { type: 'error'; payload: Error };\n\nexport function useFetch<T = unknown>(\n  url?: string,\n  options?: RequestInit\n): State<T> {\n  const cache = useRef<Cache<T>>({});\n\n  // Used to prevent state update if the component is unmounted\n  const cancelRequest = useRef<boolean>(false);\n\n  const initialState: State<T> = {\n    error: undefined,\n    data: undefined\n  };\n\n  // Keep state logic separated\n  const fetchReducer = (state: State<T>, action: Action<T>): State<T> => {\n    switch (action.type) {\n      case 'loading':\n        return { ...initialState };\n      case 'fetched':\n        return { ...initialState, data: action.payload };\n      case 'error':\n        return { ...initialState, error: action.payload };\n      default:\n        return state;\n    }\n  };\n\n  const [state, dispatch] = useReducer(fetchReducer, initialState);\n\n  useEffect(() => {\n    // Do nothing if the url is not given\n    if (!url) return;\n\n    cancelRequest.current = false;\n\n    const fetchData = async () => {\n      dispatch({ type: 'loading' });\n\n      // If a cache exists for this url, return it\n      if (cache.current[url]) {\n        dispatch({ type: 'fetched', payload: cache.current[url] });\n        return;\n      }\n\n      try {\n        const response = await fetch(url, options);\n        if (!response.ok) {\n          throw new Error(response.statusText);\n        }\n\n        const data = (await response.json()) as T;\n        cache.current[url] = data;\n        if (cancelRequest.current) return;\n\n        dispatch({ type: 'fetched', payload: data });\n      } catch (error) {\n        if (cancelRequest.current) return;\n\n        dispatch({ type: 'error', payload: error as Error });\n      }\n    };\n\n    void fetchData();\n\n    // Use the cleanup function for avoiding a possibly...\n    // ...state update after the component was unmounted\n    return () => {\n      cancelRequest.current = true;\n    };\n  }, [url]);\n\n  return state;\n}\n"],"names":["useFetch","url","options","cache","useRef","cancelRequest","initialState","fetchReducer","state","action","dispatch","useReducer","useEffect","response","data","error"],"mappings":"yCAegB,SAAAA,EACdC,EACAC,EACU,CACJ,MAAAC,EAAQC,SAAiB,CAAA,CAAE,EAG3BC,EAAgBD,SAAgB,EAAK,EAErCE,EAAyB,CAC7B,MAAO,OACP,KAAM,MAAA,EAIFC,EAAe,CAACC,EAAiBC,IAAgC,CACrE,OAAQA,EAAO,KAAM,CACnB,IAAK,UACI,MAAA,CAAE,GAAGH,GACd,IAAK,UACH,MAAO,CAAE,GAAGA,EAAc,KAAMG,EAAO,OAAQ,EACjD,IAAK,QACH,MAAO,CAAE,GAAGH,EAAc,MAAOG,EAAO,OAAQ,EAClD,QACSD,OAAAA,CACX,CAAA,EAGI,CAACA,EAAOE,CAAQ,EAAIC,EAAAA,WAAWJ,EAAcD,CAAY,EAE/DM,OAAAA,EAAAA,UAAU,IAEHX,GAELI,EAAc,QAAU,IAEN,SAAY,CAIxB,GAHKK,EAAA,CAAE,KAAM,SAAA,CAAW,EAGxBP,EAAM,QAAQF,CAAG,EAAG,CACbS,EAAA,CAAE,KAAM,UAAW,QAASP,EAAM,QAAQF,CAAG,EAAG,EACzD,OAGE,GAAA,CACF,MAAMY,EAAW,MAAM,MAAMZ,EAAKC,CAAO,EACrC,GAAA,CAACW,EAAS,GACN,MAAA,IAAI,MAAMA,EAAS,UAAU,EAG/B,MAAAC,EAAQ,MAAMD,EAAS,OAE7B,GADMV,EAAA,QAAQF,CAAG,EAAIa,EACjBT,EAAc,QAAS,OAE3BK,EAAS,CAAE,KAAM,UAAW,QAASI,CAAM,CAAA,QACpCC,GACP,GAAIV,EAAc,QAAS,OAE3BK,EAAS,CAAE,KAAM,QAAS,QAASK,CAAgB,CAAA,CACrD,CAAA,GAGa,EAIR,IAAM,CACXV,EAAc,QAAU,EAAA,GApChB,OAsCT,CAACJ,CAAG,CAAC,EAEDO,CACT"}