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 の基礎

xdev.asia

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.AsyncData を使用する

<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:真
CSRクライアント側のみSSR:偽
SSG静的サイトの生成npx nuxi 生成
ISR増分静的 + 再検証ルートルール
SWR再検証中に失効するルートルール
// 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 ルート — サーバールート、ミドルウェア、データベース。