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.