UNPKG

use-async-resource

Version:

A custom React hook for simple data fetching with React Suspense

76 lines (64 loc) 2.21 kB
import { ApiFn, DataOrModifiedFn, ModifierFn } from './types'; import { resourceCache } from './cache'; /** * Wrapper for an apiFunction without params. * It only takes the api function as an argument. * It returns a data reader with an optional modifier function. * * @param apiFn A typical api function that doesn't take any parameters. */ export function initializeDataReader<ResponseType>( apiFn: ApiFn<ResponseType>, ): DataOrModifiedFn<ResponseType>; /** * Wrapper for an apiFunction with params. * It takes the api function and all its expected arguments. * Also returns a data reader with an optional modifier function. * * @param apiFn A typical api function with parameters. * @param parameters An arbitrary number of parameters. */ export function initializeDataReader<ResponseType, ArgTypes extends unknown[]>( apiFn: ApiFn<ResponseType, ArgTypes>, ...parameters: ArgTypes ): DataOrModifiedFn<ResponseType>; // implementation that covers the above overloads export function initializeDataReader<ResponseType, ArgTypes extends unknown[] = []>( apiFn: ApiFn<ResponseType, ArgTypes>, ...parameters: ArgTypes ) { type AsyncStatus = 'init' | 'done' | 'error'; const apiFnCache = resourceCache(apiFn); const cachedResource = apiFnCache.get(...parameters); if (cachedResource) { return cachedResource; } let data: ResponseType; let status: AsyncStatus = 'init'; let error: unknown; const fetchingPromise = apiFn(...parameters) .then((result) => { data = result; status = 'done'; return result; }) .catch((err) => { error = err; status = 'error'; }); // the return type successfully satisfies DataOrModifiedFn<ResponseType> function dataReaderFn(): ResponseType; function dataReaderFn<M>(modifier: ModifierFn<ResponseType, M>): M; function dataReaderFn<M>(modifier?: ModifierFn<ResponseType, M>) { if (status === 'init') { throw fetchingPromise; } else if (status === 'error') { throw error; } return typeof modifier === 'function' ? (modifier(data) as M) : (data as ResponseType); } apiFnCache.set(dataReaderFn, ...parameters); return dataReaderFn; }