1. useFetch
<script setup lang="ts">
interface Post {
id: string
title: string
content: string
}
// Basic usage — SSR-friendly
const { data: posts, status, error, refresh } = await useFetch<Post[]>('/api/posts')
// With options
const { data: post } = await useFetch<Post>(`/api/posts/${slug}`, {
pick: ['title', 'content'], // Only transfer these fields
transform: (data) => ({
...data,
title: data.title.toUpperCase(),
}),
})
// With query params
const page = ref(1)
const { data } = await useFetch('/api/posts', {
query: { page, limit: 10 }, // Reactive — auto-refetch
watch: [page], // Watch for changes
})
</script>
<template>
<div v-if="status === 'pending'">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<div v-else>
<div v-for="post in posts" :key="post.id">{{ post.title }}</div>
<button @click="refresh()">Refresh</button>
</div>
</template>
2. useAsyncData
<script setup lang="ts">
// Khi cần custom fetching logic
const { data: user } = await useAsyncData('user', () => {
return $fetch('/api/user/me')
})
// Multiple parallel fetches
const [{ data: posts }, { data: categories }] = await Promise.all([
useFetch('/api/posts'),
useFetch('/api/categories'),
])
// Cached key — dedup requests
const { data } = await useAsyncData(
`post-${slug}`, // Unique key
() => $fetch(`/api/posts/${slug}`),
{ dedupe: 'cancel' } // Cancel previous request
)
</script>
3. Lazy Fetching
<script setup lang="ts">
// useLazyFetch — không block navigation, render ngay
const { data, pending } = useLazyFetch('/api/posts')
// useLazyAsyncData
const { data: comments, pending: loadingComments } = useLazyAsyncData(
'comments',
() => $fetch(`/api/posts/${slug}/comments`)
)
</script>
<template>
<div>
<div v-if="pending">Loading posts...</div>
<div v-else v-for="post in data" :key="post.id">{{ post.title }}</div>
<!-- Comments load separately -->
<div v-if="loadingComments">Loading comments...</div>
<div v-else v-for="c in comments" :key="c.id">{{ c.text }}</div>
</div>
</template>
4. Rendering Modes
| Mode | Description | Config |
|---|---|---|
| SSR | Server-side rendering (default) | ssr: true |
| CSR | Client-side only | ssr: false |
| SSG | Static site generation | npx nuxi generate |
| ISR | Incremental static + revalidation | Route rules |
| SWR | Stale-while-revalidate | Route rules |
// nuxt.config.ts — Hybrid rendering
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // SSG
'/blog/**': { isr: 3600 }, // ISR — revalidate 1h
'/dashboard/**': { ssr: false }, // CSR only
'/api/**': { cors: true }, // API CORS
'/admin/**': { ssr: false, robots: false }, // CSR + no index
},
})
5. $fetch — Direct HTTP
// $fetch — dùng trong event handlers, không trong setup
async function deletePost(id: string) {
await $fetch(`/api/posts/${id}`, {
method: 'DELETE',
})
await refreshNuxtData('posts') // Refresh cached data
}
// POST
const result = await $fetch('/api/posts', {
method: 'POST',
body: { title: 'New Post', content: '...' },
})
Next article: Nitro Server Engine & API Routes — server routes, middleware, database.