Next.js 如何在服務(wù)器組件和客戶端組件中獲取數(shù)據(jù)

2025-03-21 09:59 更新

如何在服務(wù)器組件和客戶端組件中獲取數(shù)據(jù)

本頁將指導(dǎo)你如何在服務(wù)器組件和客戶端組件中獲取數(shù)據(jù),以及如何流式傳輸依賴數(shù)據(jù)的內(nèi)容。

服務(wù)器組件

你可以在服務(wù)器組件中使用以下方法獲取數(shù)據(jù):

  1. fetch API
  2. ORM 或數(shù)據(jù)庫

使用 fetch API

要使用 fetch API 獲取數(shù)據(jù),將組件轉(zhuǎn)換為異步函數(shù),并等待 fetch 調(diào)用。例如:

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 或數(shù)據(jù)庫

你也可以使用 ORM 或數(shù)據(jù)庫獲取數(shù)據(jù),將組件轉(zhuǎn)換為異步函數(shù),并等待調(diào)用:

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>
  )
}

客戶端組件

在客戶端組件中獲取數(shù)據(jù)有兩種方法:

  1. React 的 use 鉤子
  2. 社區(qū)庫(如 SWR 或 React Query)

使用 use 鉤子

你可以使用 React 的 use 鉤子從服務(wù)器到客戶端流式傳輸數(shù)據(jù)。首先在服務(wù)器組件中獲取數(shù)據(jù),并將承諾傳遞給客戶端組件作為屬性:

import Posts from '@/app/ui/posts'
import { Suspense } from 'react'


export default function Page() {
  // 不要等待數(shù)據(jù)獲取函數(shù)
  const posts = getPosts()


  return (
    <Suspense fallback={<div>加載中...</div>}>
      <Posts posts={posts} />
    </Suspense>
  )
}

然后,在客戶端組件中,使用 use 鉤子讀取承諾:

'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> 邊界中。這意味著在承諾解決之前會顯示備用內(nèi)容。有關(guān)流式傳輸?shù)母嘈畔?,請參閱相關(guān)文檔。

你還可以使用 SWR 或 React Query 等社區(qū)庫在客戶端組件中獲取數(shù)據(jù)。這些庫有自己的緩存、流式傳輸和其他功能的語義。例如,使用 SWR:

'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>加載中...</div>
  if (error) return <div>錯誤: {error.message}</div>


  return (
    <ul>
      {data.map((post: { id: string; title: string }) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

流式傳輸

警告:下面的內(nèi)容假設(shè)你的應(yīng)用程序中啟用了 dynamicIO 配置選項。該標(biāo)志在 Next.js 15 canary 中引入。

在服務(wù)器組件中使用 async/await 時,Next.js 將選擇動態(tài)渲染。這意味著數(shù)據(jù)將為每個用戶請求在服務(wù)器上獲取并渲染。如果有任何緩慢的數(shù)據(jù)請求,整個路由將被阻止渲染。

為了提高初始加載時間和用戶體驗,你可以使用流式傳輸將頁面的 HTML 分成更小的塊,并逐步從服務(wù)器發(fā)送到客戶端。

Next.js中文教程-流式傳輸

實現(xiàn)流式傳輸有兩種方法:

  1. 使用 loading.js 文件
  2. 使用 React<Suspense> 組件

使用 loading.js

你可以在頁面所在的文件夾中創(chuàng)建一個 loading.js 文件,在獲取數(shù)據(jù)時流式傳輸整個頁面。例如,要流式傳輸 app/blog/page.js,將文件添加到 app/blog 文件夾中。

Next.js中文教程-使用loading.js

export default function Loading() {
  // 在這里定義加載 UI
  return <div>加載中...</div>
}

在導(dǎo)航時,用戶會立即看到布局和加載狀態(tài),同時頁面正在渲染。渲染完成后,新內(nèi)容將自動替換。

此方法適用于路由段(布局和頁面),但對于更精細(xì)的流式處理,您可以使用 <Suspense>

使用 <Suspense>

<Suspense> 允許你更細(xì)致地控制頁面的哪些部分要流式傳輸。例如,你可以立即顯示 <Suspense> 邊界之外的任何頁面內(nèi)容,并在邊界內(nèi)流式傳輸博客文章列表。

import { Suspense } from 'react'
import BlogList from '@/components/BlogList'
import BlogListSkeleton from '@/components/BlogListSkeleton'


export default function BlogPage() {
  return (
    <div>
      {/* 這部分內(nèi)容將立即發(fā)送到客戶端 */}
      <header>
        <h1>歡迎來到編程獅的博客</h1>
        <p>請閱讀下面的最新教程。</p>
      </header>
      <main>
        {/* 任何被 <Suspense> 包裹的內(nèi)容都將被流式傳輸 */}
        <Suspense fallback={<BlogListSkeleton />}>
          <BlogList />
        </Suspense>
      </main>
    </div>
  )
}

創(chuàng)建有意義的加載狀態(tài)

即時加載狀態(tài)是在導(dǎo)航后立即向用戶顯示的備用 UI。為了提供最佳的用戶體驗,我們建議設(shè)計有意義的加載狀態(tài),以幫助用戶了解應(yīng)用正在響應(yīng)。例如,你可以使用骨架屏和加載動畫,或者顯示未來屏幕的一小部分,如封面照片、標(biāo)題等。

在開發(fā)過程中,你可以使用 React Devtools 預(yù)覽和檢查組件的加載狀態(tài)。

API 參考

閱讀 API 參考 ,了解有關(guān)本頁中提到的功能的更多信息。

  • 獲取 擴(kuò)展 fetch 函數(shù)的 API 參考。

  • loading.js loading.js 文件的 API 參考。
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號