Lessons in this course (17)

10. Composables (reusable logic)

Intermediate★ Must knowLesson 10 of 17
ts
// 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 loading = ref(false);

  watchEffect(async onCleanup => {
    const controller = new AbortController();
    onCleanup(() => controller.abort());
    loading.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();
    } catch (e) {
      if ((e as Error).name !== "AbortError") error.value = e as Error;
    } finally {
      loading.value = false;
    }
  });
  return { data, error, loading };
}

// In a component
const { data: orders, loading } = useFetch<Order[]>(() => `/api/orders?page=${page.value}`);

Composables are functions named useXxx that use Composition API features; each call gets its own state (or share module-level state for a singleton). VueUse offers 200+ ready-made composables (useLocalStorage, useDebounceFn, useIntersectionObserver).