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.
A nice composable for fetching
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 };
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment