データのフェッチとストリーミングの方法
このページでは、サーバーコンポーネントとクライアントコンポーネントでデータをフェッチする方法を説明します。また、データに依存するコンテンツをストリーミングする方法についても説明します。
データフェッチング
サーバーコンポーネント
サーバーコンポーネントでは、以下の方法でデータをフェッチできます。
fetch
API の使用
fetch
API でデータをフェッチするには、コンポーネントを非同期関数にし、fetch
呼び出しを await します。例:
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 やデータベースクライアントを使用して安全にデータベースクエリを実行できます。コンポーネントを非同期関数にし、呼び出しを await します。
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>
)
}
クライアントコンポーネント
クライアントコンポーネントでデータをフェッチするには、次の2つの方法があります。
- React の
use
フック - SWR や React Query などのコミュニティライブラリ
use
フックの使用
React のuse
フック を使用して、サーバーからクライアントへデータをストリーミングできます。まず、サーバーコンポーネントでデータをフェッチし、その Promise をクライアントコンポーネントに props として渡します。
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 を読み取ります。
'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 が解決される間、フォールバックが表示されます。ストリーミングの詳細については、こちらをご覧ください。
コミュニティライブラリ
クライアントコンポーネントでデータをフェッチするには、SWR や React Query などのコミュニティライブラリを使用できます。これらのライブラリには、キャッシュ、ストリーミング、その他の機能に関する独自のセマンティクスがあります。例: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>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 を小さなチャンクに分割し、それらのチャンクをサーバーからクライアントへ段階的に送信できます。

アプリケーションでストリーミングを実装するには、2つの方法があります。
loading.js
ファイルを使用- React の
<Suspense>
コンポーネントを使用
loading.js
の使用
loading.js
ファイルをページの同じフォルダーに作成することで、データフェッチ中にページ全体をストリーミングできます。例えば、app/blog/page.js
をストリーミングするには、app/blog
フォルダー内にファイルを追加します。

export default function Loading() {
// Define the Loading UI here
return <div>Loading...</div>
}
ナビゲーション時、ユーザーはレイアウトとローディング状態をすぐに確認でき、その間にページがレンダリングされます。レンダリングが完了すると、新しいコンテンツが自動的に入れ替わります。

舞台裏では、loading.js
は layout.js
の中にネストされ、page.js
ファイルとそれ以降の子要素を自動的に <Suspense>
バウンダリーで囲みます。

このアプローチはルートセグメント(レイアウトとページ)に効果的ですが、よりきめ細かなストリーミングには <Suspense>
を使用できます。
<Suspense>
の使用
<Suspense>
を使用すると、ページのどの部分をストリーミングするかをより細かく制御できます。たとえば、<Suspense>
バウンダリーの外側にあるページコンテンツはすぐに表示し、バウンダリー内のブログ記事のリストをストリーミングすることができます。
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>
)
}
意味のあるローディング状態の作成
即時ローディング状態とは、ナビゲーション後にユーザーにすぐに表示されるフォールバック UI です。最高のユーザーエクスペリエンスのために、アプリが応答していることをユーザーが理解できるような、意味のあるローディング状態を設計することをお勧めします。たとえば、スケルトンやスピナー、またはカバー写真、タイトルなど、今後の画面の小さくても意味のある部分を使用できます。
開発中は、React Devtools を使用して、コンポーネントのローディング状態をプレビューおよび検査できます。
API リファレンス
この情報は役に立ちましたか?