Chuyển đến nội dung chính

第 10 課:資料擷取與 SSR

useFetch、useAsyncData、$fetch。 SSR、CSR、SSG、ISR。水合作用、有效負載最佳化。使用LazyFetch,刷新/執行。錯誤處理、載入狀態。

💻 程式設計 — 第 10 課 第 10 課:資料擷取與 SSR

Vue.js 和 Nuxt:從基礎到高級

第 3 部分:Nuxt 3 基礎知識

亞洲開發網

1.使用Fetch

<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.使用非同步數據

<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. 惰性獲取

<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. 渲染模式

模式描述配置
固態繼電器伺服器端渲染(預設)ssr: 正確
企業社會責任僅限客戶端ssr: 假
SSG靜態站點生成npx nuxi 生成
情報監視與偵察增量靜態+重新驗證路線規則
駐波比重新驗證時過時路線規則
// 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 — 直接 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: '...' },
})

下一篇: Nitro 伺服器引擎和 API 路由 — 伺服器路由、中間件、資料庫。