import {ref, Ref, UnwrapRef} from 'vue'; import useMountedState from "./useMountedState"; import {FunctionReturningPromise, PromiseType} from './misc/types'; import {useReactive, useRef} from "./index"; export type AsyncState = | { loading: boolean; error?: undefined; value?: undefined; } | { loading: true; error?: Error | undefined; value?: T; } | { loading: false; error: Error; value?: undefined; } | { loading: false; error?: undefined; value: T; }; type StateFromFunctionReturningPromise = AsyncState>>; export type AsyncFnReturn = [ StateFromFunctionReturningPromise, T ]; export default function useAsyncFn( fn: T, initialState: StateFromFunctionReturningPromise = {loading: false} ): AsyncFnReturn { const lastCallId = useRef(0); const isMounted = useMountedState(); const [state, set] = useReactive(initialState); const callback = (...args: Parameters): ReturnType => { const callId = ++lastCallId.value; state.loading = true return fn(...args).then( (value) => { isMounted() && callId === lastCallId.value && set({value, loading: false}); return value; }, (error) => { isMounted() && callId === lastCallId.value && set({error, loading: false}); return error; } ) as ReturnType; }; return [state, (callback as unknown) as T]; }