跳到內容

如何獲取資料和串流

本頁將引導您了解如何在伺服器元件客戶端元件中獲取資料。以及如何串流取決於資料的內容。

資料獲取

伺服器元件

您可以使用以下方式在伺服器元件中獲取資料

  1. fetch API
  2. ORM 或資料庫

使用 fetch API

要使用 fetch API 獲取資料,請將您的元件變成非同步函式,並等待 fetch 呼叫。例如

app/blog/page.tsx
export default async function Page() {
  const data = await fetch('https://api.vercel.app/blog')
  const posts = await data.json()
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

使用 ORM 或資料庫

您可以通過將元件變成非同步函式並等待呼叫,使用 ORM 或資料庫來獲取資料

app/blog/page.tsx
import { db, posts } from '@/lib/db'
 
export default async function Page() {
  const allPosts = await db.select().from(posts)
  return (
    <ul>
      {allPosts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

客戶端元件

在客戶端元件中,有兩種方法可以獲取資料,使用

  1. React 的 use hook
  2. 社群函式庫,例如 SWRReact Query

使用 use hook

您可以使用 React 的 use hook串流從伺服器到客戶端的資料。首先在您的伺服器元件中獲取資料,然後將 Promise 作為 prop 傳遞給您的客戶端元件

app/blog/page.tsx
import Posts from '@/app/ui/posts
import { Suspense } from 'react'
 
export default function Page() {
  // Don't await the data fetching function
  const posts = getPosts()
 
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Posts posts={posts} />
    </Suspense>
  )
}

然後,在您的客戶端元件中,使用 use hook 來讀取 Promise

app/ui/posts.tsx
'use client'
import { use } from 'react'
 
export default function Posts({
  posts,
}: {
  posts: Promise<{ id: string; title: string }[]>
}) {
  const allPosts = use(posts)
 
  return (
    <ul>
      {allPosts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

在上面的範例中,您需要將 <Posts /> 元件包裝在 <Suspense> 邊界 中。這表示在 Promise 解析期間將顯示 fallback。了解更多關於串流的資訊。

社群函式庫

您可以使用社群函式庫,例如 SWRReact Query 在客戶端元件中獲取資料。這些函式庫有自己的語義用於快取、串流和其他功能。例如,使用 SWR

app/blog/page.tsx
'use client'
import useSWR from 'swr'
 
const fetcher = (url) => fetch(url).then((r) => r.json())
 
export default function BlogPage() {
  const { data, error, isLoading } = useSWR(
    'https://api.vercel.app/blog',
    fetcher
  )
 
  if (isLoading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>
 
  return (
    <ul>
      {data.map((post: { id: string; title: string }) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

串流

警告: 以下內容假設您的應用程式中已啟用 dynamicIO 設定選項。此標誌在 Next.js 15 canary 版本中引入。

當在伺服器元件中使用 async/await 時,Next.js 將選擇加入動態渲染。這表示資料將在伺服器上針對每個使用者請求獲取和渲染。如果有任何緩慢的資料請求,整個路由將被阻止渲染。

為了改善初始載入時間和使用者體驗,您可以使用串流將頁面的 HTML 分解為更小的區塊,並逐步將這些區塊從伺服器發送到客戶端。

How Server Rendering with Streaming Works

您可以使用兩種方法在應用程式中實作串流

  1. 使用 loading.js 檔案
  2. 使用 React 的 <Suspense> 元件

使用 loading.js

您可以在與頁面相同的資料夾中建立 loading.js 檔案,以在獲取資料時串流整個頁面。例如,要串流 app/blog/page.js,請將檔案新增到 app/blog 資料夾中。

Blog folder structure with loading.js file
app/blog/loading.tsx
export default function Loading() {
  // Define the Loading UI here
  return <div>Loading...</div>
}

在導航時,使用者將立即看到版面配置和載入狀態,同時頁面正在渲染。新的內容將在渲染完成後自動替換。

Loading UI

在幕後,loading.js 將巢狀在 layout.js 內部,並自動將 page.js 檔案和下方任何子項目包裝在 <Suspense> 邊界中。

loading.js overview

此方法適用於路由區段(版面配置和頁面),但對於更精細的串流,您可以使用 <Suspense>

使用 <Suspense>

<Suspense> 允許您更精細地控制要串流的頁面部分。例如,您可以立即顯示 <Suspense> 邊界之外的任何頁面內容,並串流邊界內的部落格文章列表。

app/blog/page.tsx
import { Suspense } from 'react'
import BlogList from '@/components/BlogList'
import BlogListSkeleton from '@/components/BlogListSkeleton'
 
export default function BlogPage() {
  return (
    <div>
      {/* This content will be sent to the client immediately */}
      <header>
        <h1>Welcome to the Blog</h1>
        <p>Read the latest posts below.</p>
      </header>
      <main>
        {/* Any content wrapped in a <Suspense> boundary will be streamed */}
        <Suspense fallback={<BlogListSkeleton />}>
          <BlogList />
        </Suspense>
      </main>
    </div>
  )
}

建立有意義的載入狀態

即時載入狀態是導航後立即向使用者顯示的 fallback UI。為了獲得最佳使用者體驗,我們建議設計有意義的載入狀態,以幫助使用者了解應用程式正在回應。例如,您可以使用骨架畫面和旋轉器,或未來畫面的小而有意義的部分,例如封面照片、標題等。

在開發中,您可以使用 React Devtools 預覽和檢查元件的載入狀態。

API 參考

閱讀 API 參考,以了解更多關於本頁中提及的功能。