import { useCallback, useDebugValue, useRef, useState } from 'react' import { store } from './store' import { Fetcher, Options, Url } from './types' export const setFetcher = (fetcher: Fetcher) => { store.setFetcher(fetcher) } const checkHasCachedDataInRequest = (url: Url) => { return store.get(url) } const useSWF = (baseUrl: Url, fetcher?: Fetcher) => { const loading = useRef(false) const error = useRef(undefined) const cachedUrl = useRef('') const result = useRef(undefined) const previousOptions = useRef(undefined) const request = useRef(fetcher ?? store.getFetcher()) const [, forceRender] = useState(0) const reRender = () => { forceRender(prev => prev + 1) } const send = useCallback( async (options?: Options, url?: Url): Promise<{ result: S | undefined; error: Response | undefined }> => { loading.current = true result.current = checkHasCachedDataInRequest(url ?? baseUrl) reRender() const { noCache, ...rest } = options previousOptions.current = rest try { const data = (await request.current(url ?? baseUrl, rest)) as S !noCache && store.set(url ?? baseUrl, data) cachedUrl.current = url ?? baseUrl result.current = data error.current = undefined } catch (err) { error.current = err result.current = undefined } loading.current = false reRender() return { result: result.current, error: error.current } }, [baseUrl] ) const preFetch = useCallback( async (options?: Options, url?: Url) => { const { noCache, ...rest } = options previousOptions.current = rest try { const data = (await request.current(url ?? baseUrl, rest)) as S !noCache && store.set(url ?? baseUrl, data) cachedUrl.current = url ?? baseUrl result.current = data error.current = undefined } catch (err) { error.current = err result.current = undefined } }, [baseUrl] ) const revalidate = useCallback(async (options?: Options) => { try { const data = (await request.current(cachedUrl.current, previousOptions.current)) as S !options.noCache && store.set(cachedUrl.current, data) result.current = data error.current = undefined } catch (err) { error.current = err result.current = undefined } reRender() }, []) const config = { result: result.current, error: error.current, loading: loading.current, send, preFetch, revalidate, } useDebugValue(config) return config } export default useSWF