JAVASCRIPT
Vue 3 Custom Composable for Reactive Data Fetching
Create a reusable Vue 3 Composition API composable (`useFetch`) to handle asynchronous data fetching, loading states, and error management efficiently.
// 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 on new fetch
data.value = null;
error.value = null;
loading.value = true;
try {
// toValue handles both ref and non-ref values
const response = await fetch(toValue(urlRef));
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
data.value = await response.json();
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
}
// Automatically fetch when component mounts
onMounted(doFetch);
// You can also watch urlRef if you want to re-fetch on URL change
// import { watch } from 'vue';
// watch(urlRef, doFetch);
return { data, error, loading, doFetch };
}
// App.vue (or any component)
<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="doFetch">Refetch Posts</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useFetch } from './composables/useFetch';
const postsUrl = ref('https://jsonplaceholder.typicode.com/posts?_limit=5');
const { data, error, loading, doFetch } = useFetch(postsUrl);
</script>
How it works: This snippet creates a `useFetch` composable that encapsulates logic for making API calls. It manages loading, data, and error states using Vue's `ref` and `onMounted` lifecycle hook. Components can then easily consume this composable to fetch data, providing a clean separation of concerns and reusability for asynchronous operations. The `toValue` utility handles reactive and non-reactive URLs, allowing flexibility in how the URL is passed.