Skip to content

Instantly share code, notes, and snippets.

@BarishNamazov
Created January 29, 2024 22:12
Show Gist options
  • Select an option

  • Save BarishNamazov/30204a201efaa0e45702b4fb331d13b9 to your computer and use it in GitHub Desktop.

Select an option

Save BarishNamazov/30204a201efaa0e45702b4fb331d13b9 to your computer and use it in GitHub Desktop.

Revisions

  1. BarishNamazov created this gist Jan 29, 2024.
    57 changes: 57 additions & 0 deletions useApi.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    import { ref, watch } from 'vue';

    type Func = (...args: any[]) => any;

    const apiState = reactive({
    triggers: {} as Record<string, number>
    });

    export function refetchApi(key: string) {
    apiState.triggers[key] = (apiState.triggers[key] || 0) + 1;
    }

    export function useApi<F extends Func>(apiFunction: F, key: string) {
    return (options?: { silentFetch?: boolean; silentError?: boolean }) => {
    const o = options || {};
    o.silentFetch = o.silentFetch || false;
    o.silentError = o.silentError || false;

    const data = ref<Awaited<ReturnType<F>> | null>(null);
    const error = ref<string | null>(null);
    const loading = ref(false);
    let params: Parameters<F> | null = null;
    let firstRun = true;

    const execute = async (...args: Parameters<F>): Promise<void> => {
    params = args;
    if (firstRun || !o.silentFetch) {
    loading.value = true;
    }
    firstRun = false;
    error.value = null;
    let err = null;
    try {
    data.value = await apiFunction(...args);
    } catch (e) {
    error.value = e instanceof Error ? e.message : String(e);
    err = e;
    } finally {
    loading.value = false;
    }

    // Throw error to be caught by the caller
    if (err && !o.silentError) {
    throw err;
    }
    };

    watch(
    () => apiState.triggers[key],
    async () => {
    void execute.call(null, ...params!);
    }
    );

    return { data, error, loading, execute };
    };
    }