Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.0 KiB
5.0 KiB
name, description
| name | description |
|---|---|
| data-fetching | useFetch, useAsyncData, and $fetch for SSR-friendly data fetching |
Data Fetching
Nuxt provides composables for SSR-friendly data fetching that prevent double-fetching and handle hydration.
Overview
$fetch- Basic fetch utility (use for client-side events)useFetch- SSR-safe wrapper around $fetch (use for component data)useAsyncData- SSR-safe wrapper for any async function
useFetch
Primary composable for fetching data in components:
<script setup lang="ts">
const { data, status, error, refresh, clear } = await useFetch('/api/posts')
</script>
<template>
<div v-if="status === 'pending'">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<div v-else>
<article v-for="post in data" :key="post.id">
{{ post.title }}
</article>
</div>
</template>
With Options
const { data } = await useFetch('/api/posts', {
// Query parameters
query: { page: 1, limit: 10 },
// Request body (for POST/PUT)
body: { title: 'New Post' },
// HTTP method
method: 'POST',
// Only pick specific fields
pick: ['id', 'title'],
// Transform response
transform: (posts) => posts.map(p => ({ ...p, slug: slugify(p.title) })),
// Custom key for caching
key: 'posts-list',
// Don't fetch on server
server: false,
// Don't block navigation
lazy: true,
// Don't fetch immediately
immediate: false,
// Default value
default: () => [],
})
Reactive Parameters
<script setup lang="ts">
const page = ref(1)
const { data } = await useFetch('/api/posts', {
query: { page }, // Automatically refetches when page changes
})
</script>
Computed URL
<script setup lang="ts">
const id = ref(1)
const { data } = await useFetch(() => `/api/posts/${id.value}`)
// Refetches when id changes
</script>
useAsyncData
For wrapping any async function:
<script setup lang="ts">
const { data, error } = await useAsyncData('user', () => {
return myCustomFetch('/user/profile')
})
</script>
Multiple Requests
<script setup lang="ts">
const { data } = await useAsyncData('cart', async () => {
const [coupons, offers] = await Promise.all([
$fetch('/api/coupons'),
$fetch('/api/offers'),
])
return { coupons, offers }
})
</script>
$fetch
For client-side events (form submissions, button clicks):
<script setup lang="ts">
async function submitForm() {
const result = await $fetch('/api/submit', {
method: 'POST',
body: { name: 'John' },
})
}
</script>
Important: Don't use $fetch alone in setup for initial data - it will fetch twice (server + client). Use useFetch or useAsyncData instead.
Return Values
All composables return:
| Property | Type | Description |
|---|---|---|
data |
Ref<T> |
Fetched data |
error |
Ref<Error> |
Error if request failed |
status |
Ref<'idle' | 'pending' | 'success' | 'error'> |
Request status |
refresh |
() => Promise |
Refetch data |
execute |
() => Promise |
Alias for refresh |
clear |
() => void |
Reset data and error |
Lazy Fetching
Don't block navigation:
<script setup lang="ts">
// Using lazy option
const { data, status } = await useFetch('/api/posts', { lazy: true })
// Or use lazy variants
const { data, status } = await useLazyFetch('/api/posts')
const { data, status } = await useLazyAsyncData('key', fetchFn)
</script>
Refresh & Watch
<script setup lang="ts">
const category = ref('tech')
const { data, refresh } = await useFetch('/api/posts', {
query: { category },
// Auto-refresh when category changes
watch: [category],
})
// Manual refresh
const refreshData = () => refresh()
</script>
Caching
Data is cached by key. Share data across components:
<script setup lang="ts">
// In component A
const { data } = await useFetch('/api/user', { key: 'current-user' })
// In component B - uses cached data
const { data } = useNuxtData('current-user')
</script>
Refresh cached data globally:
// Refresh specific key
await refreshNuxtData('current-user')
// Refresh all data
await refreshNuxtData()
// Clear cached data
clearNuxtData('current-user')
Interceptors
const { data } = await useFetch('/api/auth', {
onRequest({ options }) {
options.headers.set('Authorization', `Bearer ${token}`)
},
onRequestError({ error }) {
console.error('Request failed:', error)
},
onResponse({ response }) {
// Process response
},
onResponseError({ response }) {
if (response.status === 401) {
navigateTo('/login')
}
},
})
Passing Headers (SSR)
useFetch automatically proxies cookies/headers from client to server. For $fetch:
<script setup lang="ts">
const headers = useRequestHeaders(['cookie'])
const data = await $fetch('/api/user', { headers })
</script>