跳转至

获取数据

原文地址:https://nextjs.org/docs/app/getting-started/fetching-data

本页将引导您了解如何在服务器和客户端组件中获取数据,以及如何流式传输依赖于数据的组件。

1. 获取数据

1.1 服务端组件

您可以使用任何异步 I/O 在服务器组件中获取数据,例如:

  1. fetch API 接口;
  2. ORM 或数据库
  3. 使用 Node.js API(例如 fs 从文件系统读取数据)

1.1.1 使用 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}>nnnnhhhyjjkkfgvrx{post.title}</li>
      ))}
    </ul>
  )
}

备注

默认情况下不缓存 fetch 响应。但是,Next.js 将预渲染路由,并且输出将被缓存以提高性能。如果你想选择动态渲染,请使用 { cache: 'no-store' } 选项。请参考 fetch API。

在开发过程中,您可以记录 fetch 调用以获得更好的可见性和调试。请参阅 logging API 参考。

1.1.2 使用 ORM 或数据库

由于服务端组件是在服务器上呈现的,因此我们可以使用 ORM 或数据库客户端安全地进行数据库查询。将服务端组件转换为异步函数,并等待调用:

app/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.2 客户端组件

有两种方法可以在客户端组件中获取数据,使用:

  • React 的 use 钩子
  • 像 SWR 或 React Query 这样的社区库

1.2.1 使用 use 钩子流式传输数据

我们可以使用 React 的 use 钩子将数据从服务端流式传输到客户端。首先在服务端组件中获取数据,并将 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 钩子来读取 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>
  )
}

1.2.2 使用社区库

您可以使用 SWR 或 React 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>
  )
}

2. 重复请求和缓存数据

消除重复 fetch 请求的一种方法是使用请求记忆,这种机制使得具有相同 URL 的 GETHEADfetch 调用以及单个渲染过程中的选项将合并到一个请求中。这是自动发生的,我们可以通过向 fetch 传递 Abort 信号来选择退出。

请求记忆的范围是请求的生命周期。

您还可以使用 Next.js 的数据缓存来删除重复的 fetch 请求,例如通过在 fetch 选项中设置 cache: 'force-cache'

数据缓存允许在当前渲染通道和传入请求之间共享数据。

如果您不使用 fetch,而是直接使用 ORM 或数据库,则可以使用 React cache 功能包装数据访问。