import { useCallback, useState } from 'react'; import { useAlive } from './useAlive'; export enum AsyncStatus { Idle = 'idle', Loading = 'loading', Success = 'success', Error = 'error', } export type AsyncIdle = { status: AsyncStatus.Idle; }; export type AsyncLoading = { status: AsyncStatus.Loading; }; export type AsyncSuccess = { status: AsyncStatus.Success; data: T; }; export type AsyncError = { status: AsyncStatus.Error; error: unknown; }; export type AsyncState = AsyncIdle | AsyncLoading | AsyncSuccess | AsyncError; export type AsyncCallback = (...args: TArgs) => Promise; export const useAsyncCallback = ( asyncCallback: AsyncCallback ): [AsyncState, AsyncCallback] => { const [state, setState] = useState>({ status: AsyncStatus.Idle, }); const alive = useAlive(); const callback: AsyncCallback = useCallback( async (...args) => { setState({ status: AsyncStatus.Loading, }); try { const data = await asyncCallback(...args); if (alive()) { setState({ status: AsyncStatus.Success, data, }); } return data; } catch (e) { if (alive()) { setState({ status: AsyncStatus.Error, error: e, }); } throw e; } }, [asyncCallback, alive] ); return [state, callback]; };