Vue cookbook · Intermediate
Fetch, refresh and share data with Nuxt useFetch
Pages refetch data in the browser after SSR, and lists don't update after mutations.
Approach
Use useFetch with reactive query options so it refetches when filters change, call refresh() after
mutations, and share cached data between components with the same key (read it with useNuxtData).
Solution
<!-- app/pages/orders.vue -->
<script setup lang="ts">
const status = ref<"all" | "open" | "shipped">("all");
const page = ref(1);
const { data, pending, error, refresh } = await useFetch("/api/orders", {
key: "orders",
query: { status, page }, // refetches when these change
transform: (res: { items: { id: string; total: number }[]; pages: number }) => res,
});
async function cancel(id: string) {
await $fetch(`/api/orders/${id}/cancel`, { method: "POST" }); // $fetch in event handlers is fine
await refresh();
}
</script>
<template>
<select v-model="status">
<option value="all">All</option>
<option value="open">Open</option>
<option value="shipped">Shipped</option>
</select>
<p v-if="pending">Loading...</p>
<p v-else-if="error">Couldn't load orders.</p>
<ul v-else>
<li v-for="order in data?.items" :key="order.id">
{{ order.id }}: {{ order.total }}
<button @click="cancel(order.id)">Cancel</button>
</li>
</ul>
</template>
Pitfalls
await $fetch()in<script setup>, which runs twice (server and client).- Building the URL string from refs (
/api/orders?page=${page.value}) instead of the reactivequeryoption, so it doesn't refetch. - Reusing a key for different data.
Variations
refreshNuxtData("orders")refreshes from anywhere by key.lazy: truerenders the page immediately and showspendingwhile loading client-side.
Further reading: useFetch
Reference: https://nuxt.com/docs/4.x/api/composables/use-fetch
More Vue recipes
- Access child component methods with template refs and defineExpose
- Add SEO metadata and structured data in Nuxt
- Build an accessible modal with Teleport
- Build custom inputs with defineModel and modifiers
- Catch component errors with an error boundary
- Debounce user input with a custom ref
- Fetch data in a composable and cancel stale requests
- Implement a dark mode toggle that respects system settings