JAVASCRIPT

Creating a Reusable Vue 3 Composable for Data Fetching

Learn to build a powerful and reusable data fetching composable in Vue 3 using the Composition API, `ref`, and lifecycle hooks for clean asynchronous data management.

// composables/useFetch.js
import { ref, onMounted, watch } from 'vue';

export function useFetch(url) {
  const data = ref(null);
  const error = ref(null);
  const loading = ref(true);

  async function doFetch() {
    loading.value = true;
    error.value = null;
    try {
      const res = await fetch(url.value || url); // Handle ref or direct string
      if (!res.ok) {
        throw new Error(`HTTP error! status: ${res.status}`);
      }
      data.value = await res.json();
    } catch (e) {
      error.value = e;
    } finally {
      loading.value = false;
    }
  }

  onMounted(() => {
    doFetch();
  });

  // Re-fetch if the URL changes (if it's a ref)
  if (typeof url === 'object' && url !== null && 'value' in url) {
    watch(url, doFetch);
  }

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

// components/MyComponent.vue
<template>
  <div>
    <div v-if="loading">Loading posts...</div>
    <div v-else-if="error">Error: {{ error.message }}</div>
    <ul v-else>
      <li v-for="post in data" :key="post.id">{{ post.title }}</li>
    </ul>
    <button @click="refreshData">Refresh</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useFetch } from '../composables/useFetch';

const postId = ref(1); // Example dynamic URL part
const apiUrl = ref(`https://jsonplaceholder.typicode.com/posts?_limit=5`); // Can be dynamic

// Using the composable
const { data, error, loading, doFetch: refreshData } = useFetch(apiUrl);

// Example of changing the URL to trigger re-fetch (if apiUrl was reactive)
// setTimeout(() => {
//   apiUrl.value = 'https://jsonplaceholder.typicode.com/todos?_limit=3';
// }, 5000);
</script>
How it works: This snippet demonstrates creating a reusable `useFetch` composable in Vue 3's Composition API. It encapsulates data fetching logic, providing reactive `data`, `error`, and `loading` states. The `onMounted` hook initiates the fetch operation, and importantly, it uses a `watch` effect to automatically re-fetch data if the provided URL (when passed as a `ref`) changes. This pattern promotes clean, reusable, and testable code for asynchronous operations within your Vue applications, making it easy to integrate data fetching into any component.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs