Vue.js
Beginner
1 min read
Building Reusable Composables
Example
// src/composables/useFetch.ts
import { ref, watchEffect, toValue, type MaybeRefOrGetter } from 'vue';
export function useFetch<T>(url: MaybeRefOrGetter<string>) {
const data = ref<T | null>(null);
const error = ref<Error | null>(null);
const isLoading = ref(false);
watchEffect(async (onCleanup) => {
const controller = new AbortController();
onCleanup(() => controller.abort());
isLoading.value = true;
error.value = null;
try {
const res = await fetch(toValue(url), { signal: controller.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
data.value = (await res.json()) as T;
} catch (e) {
if ((e as Error).name !== 'AbortError') error.value = e as Error;
} finally {
isLoading.value = false;
}
});
return { data, error, isLoading };
}
// ── Component usage ───────────────────────────
<script setup lang="ts">
import { ref, computed } from 'vue';
import { useFetch } from '@/composables/useFetch';
const userId = ref(1);
const url = computed(() => `/api/users/${userId.value}`);
const { data: user, isLoading, error } = useFetch(url);
</script>
<template>
<p v-if="isLoading">Loading…</p>
<p v-else-if="error">{{ error.message }}</p>
<pre v-else>{{ user }}</pre>
</template>