JAVASCRIPT

Building a Reusable `useFetch` Composable for API Calls

Create a custom Vue 3 composable to encapsulate data fetching logic, providing reactive state for loading, errors, and fetched data across multiple components easily.

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

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

  async function doFetch() {
    // Reset state before new fetch
    data.value = null;
    error.value = null;
    loading.value = true;

    try {
      // toValue handles both refs and plain values
      const res = await fetch(toValue(urlRef));
      if (!res.ok) {
        throw new Error(`HTTP error! status: ${res.status}`);
      }
      data.value = await res.json();
    } catch (err) {
      error.value = err;
    } finally {
      loading.value = false;
    }
  }

  // Initial fetch when component mounts
  onMounted(() => {
    doFetch();
  });

  // Optionally, refetch when urlRef changes (can be added with watch)
  // watch(urlRef, doFetch, { immediate: true });

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

// src/components/DataFetcher.vue
<template>
  <div>
    <h1>User Data</h1>
    <p v-if="loading">Loading user data...</p>
    <p v-if="error">Error: {{ error.message }}</p>
    <div v-if="data">
      <p>Name: {{ data.name }}</p>
      <p>Email: {{ data.email }}</p>
    </div>
    <button @click="refetchData">Refetch</button>
  </div>
</template>

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

const userId = ref(1); // Could be dynamic
const url = ref(`https://jsonplaceholder.typicode.com/users/${userId.value}`);

const { data, error, loading, doFetch: refetchData } = useFetch(url);

// Example of changing URL and triggering a refetch (requires watch in composable)
// setTimeout(() => {
//   userId.value = 2;
//   url.value = `https://jsonplaceholder.typicode.com/users/${userId.value}`;
//   // If watch is enabled in useFetch, this will refetch automatically.
//   // Otherwise, you'd call refetchData explicitly here.
// }, 3000);
</script>
How it works: This snippet creates a `useFetch` composable that encapsulates the logic for making API calls. It manages reactive `data`, `error`, and `loading` states. The `DataFetcher.vue` component demonstrates how to use this composable, making an initial API call on mount and providing a mechanism to refetch data. This pattern promotes reusability and separation of concerns for data fetching logic.

Need help integrating this into your project?

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

Hire DigitalCodeLabs