Data Fetching

データフェッチング

データフェッチングとは?

Next.js のデータフェッチングは、ウェブサイトが情報を取得する方法を教えてくれます。例えば、あなたが図書館に行って本を借りるとき、それはデータを"フェッチ"(取得)することと同じです。Next.js は、この情報の取得をどのように行うかをコントロールする方法を提供します。

Next.js の新しいデータフェッチングシステムは、"fetch()"という名前のツールを使います。これは、図書館の本を探すのに似ています。あなたが本を探すとき、その本の名前や著者の名前を知っている必要がありますよね。それと同じように、fetch()はウェブサイトがどの情報を探しているのかを知る必要があります。

そして、Next.js は情報を取得する場所によって、"サーバーコンポーネント"と"クライアントコンポーネント"の 2 つの種類に分けます。これは、本を探す場所が図書館の中のどこにあるかを知るのと同じです。例えば、ある本は子供のセクションにあり、別の本は大人のセクションにあるかもしれません。

また、Next.js は"静的データフェッチング"と"動的データフェッチング"の 2 つの方法を提供します。これは、本を借りる頻度によって異なります。静的データフェッチングは、あまり変わらない情報を取得するときに使います。これは、あなたが何度も読み返すお気に入りの本を借りるのに似ています。一方、動的データフェッチングは、頻繁に変わる情報を取得するときに使います。これは、新しい本を探しに行くのに似ています。

Next.js は"キャッシング"と"再検証"の 2 つの機能を提供します。キャッシングは、一度取得した情報を保存しておくことで、次回から同じ情報をすぐに取得できるようにする機能です。これは、お気に入りの本を家に持ち帰ってすぐに読めるようにするのに似ています。一方、再検証は、情報が古くなったときに新しい情報を取得する機能です。これは、新しい版の本が出たときに、古い版の本を返して新しい版を借りるのに似ています。

fetch()メソッドの解説

それでは、Data Fetching: Fetching | Next.jsについて、解説しましょう。

上のページは、Next.js アプリケーションでデータを取得する新しい方法について説明しています。

この新しい方法は、fetch()という Web API をベースにしています。fetch()は、リモートのリソースを取得するための API で、Promise を返します。Promise とは、未来の結果を表すオブジェクトで、その結果がまだ利用できない場合でも、それを扱う方法を提供します。

例えば、あなたが図書館で本を借りるとき、その本がすぐに手元にある場合と、他の人が借りていて待たなければならない場合がありますよね。このとき、図書館から本を借りる行為は、fetch()と似ています。そして、本がすぐに手元にあるか、または待っている間に他のことをするかは、Promise が表している状況に似ています。

そして、次のソースコードは、外部の API からデータを取得するためのものです。

async function getData() {
  const res = await fetch('https://api.example.com/...')
  if (!res.ok) {
    throw new Error('Failed to fetch data')
  }
  return res.json()
}

export default async function Page() {
  const data = await getData()
  return <main></main>
}

まず、getDataという関数が定義されています。この関数は、指定された URL からデータを取得します。そして、そのデータが正しく取得できたかどうかを確認します。もしデータが正しく取得できなかった場合は、エラーを投げます。データが正しく取得できた場合は、そのデータを JSON 形式に変換して返します。

次に、Pageという関数が定義されています。この関数は、先ほど定義したgetData関数を使ってデータを取得し、そのデータを使ってページを表示します。

例えば、図書館から本を借りるための手順を書いたものです。まず、本を探しに行きます。そして、その本があるかどうかを確認します。もし本がなかったら、エラーを出します。本があったら、その本を借りてきます。そして、その本を読んで、その内容を使って何かを作ります。たとえば、本の内容を使ってレポートを書くとか、絵を描くとかです。

このソースコードの中で、fetchというのが本を探しに行くことを表しているんですね。そして、res.okというのが本があるかどうかを確認することを表しています。throw new Errorは、本がなかったときにエラーを出すことを表しています。そして、res.json()は、本を借りてきて、その内容を読むことを表しています。

次に、Pageという関数があります。これは、本の内容を使って何かを作るための手順を書いたものです。この中で、getDataというのが本を借りてくることを表しています。そして、return <main></main>;は、本の内容を使って何かを作ることを表しています。この場合、本の内容を使ってウェブページを作っています。

このソースコードを使うと、ウェブページに表示するためのデータをインターネットから取得することができます。

パラレルデータフェッチング

"Parallel Data Fetching"とは、複数のデータを同時に取得することを指します。これは、データ取得の時間を短縮するための一つの方法です。

例えば、あなたが図書館で 2 冊の本を借りるとき、一つの方法は一冊ずつ本を探しに行くことです。しかし、これは時間がかかりますよね。もう一つの方法は、2 冊の本を同時に探しに行くことです。これなら、時間を節約できます。

公式ドキュメントのソースコードを解説します。

import Albums from './albums'

async function getArtist(username: string) {
  const res = await fetch(`https://api.example.com/artist/${username}`)
  return res.json()
}

async function getArtistAlbums(username: string) {
  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
  return res.json()
}

export default async function Page({ params: { username } }: { params: { username: string } }) {
  // Initiate both requests in parallel
  const artistData = getArtist(username)
  const albumsData = getArtistAlbums(username)

  // Wait for the promises to resolve
  const [artist, albums] = await Promise.all([artistData, albumsData])

  return (
    <>
      <h1>{artist.name}</h1>
      <Albums list={albums}></Albums>
    </>
  )
}

このソースコードは、アーティストの情報とそのアーティストのアルバムの情報を同時に取得しています。まず、getArtistgetArtistAlbumsという 2 つの関数があります。これらはそれぞれアーティストの情報とそのアーティストのアルバムの情報を取得します。

次に、Pageという関数があります。この中で、getArtistgetArtistAlbumsを同時に呼び出しています。そして、その結果が返ってくるのを待っています。これにより、2 つのデータ取得が同時に行われ、時間を節約することができます。

例えば、図書館で 2 冊の本を同時に借りるための手順を書いたものです。まず、一冊目の本と二冊目の本を探しに行きます。そして、その 2 冊の本があるかどうかを確認します。もし本があったら、その本を借りてきます。そして、その本の内容を使って何かを作ります。この場合、アーティストの名前とそのアルバムのリストを表示しています。

Contentful からデータを取得する

Contentful からデータを取得するためには、Contentful の API を使用します。上記のソースコードを Contentful に適用するには、fetch 関数の中で Contentful の API エンドポイントを指定し、必要なヘッダー(例えば、認証トークンなど)を設定します。

以下に、Contentful からデータを取得するための基本的なソースコードの例を示します。

async function getContentfulData(contentId: string) {
  const res = await fetch(`https://cdn.contentful.com/spaces/{space_id}/entries/${contentId}`, {
    headers: {
      Authorization: `Bearer {access_token}`,
      'Content-Type': 'application/json',
    },
  })
  if (!res.ok) {
    throw new Error('Failed to fetch data')
  }
  return res.json()
}

export default async function Page() {
  const data = await getContentfulData('your_content_id')
  return <main>{/* Render your data here */}</main>
}

このコードでは、getContentfulData関数が Contentful の API を呼び出してデータを取得します。その後、取得したデータはPage関数で使用され、ページに表示されます。

※ ただし、このコードは基本的な例なので、実際の使用には適切なエラーハンドリングやデータの形式に応じたレンダリングなど、さらなる調整が必要です。また、{space_id}{access_token}は適切な Contentful のスペース ID とアクセストークンに置き換える必要があります。

なお、Contentful のデータは通常、特定のコンテンツタイプやフィールドに基づいて構造化されているため、取得したデータの扱い方はその構造に依存します。

用語集

なんだかややこしい用語が多いので、表形式でまとめてみますね。

用語 説明
Server Components サーバーコンポーネントは、サーバー上でデータをフェッチし、その結果をクライアントに送信します。
fetch() API ネイティブの fetch() Web API をベースにした新しいデータフェッチングシステム。
Parallel and Sequential Data Fetching データフェッチングのパターンで、並行フェッチングでは、ルート内のリクエストが同時にデータをロードします。逐次フェッチングでは、リクエストが互いに依存しています。
Automatic fetch() Request Deduping 同じデータを複数のコンポーネントでフェッチする必要がある場合、Next.js は同じ入力を持つフェッチリクエストを自動的にキャッシュします。
Static and Dynamic Data Fetching 静的データフェッチングは、データがビルド時にフェッチされ、キャッシュされ、各リクエストで再利用されます。動的データフェッチングでは、各リクエストでデータをフェッチし、キャッシュせずに最新のデータを常にフェッチします。
Caching Data データをキャッシュすることで、各リクエストで元のソースから再フェッチする必要がなくなります。
Revalidating Data データが変更された場合に、キャッシュをパージして最新のデータを再フェッチするプロセス。
Streaming and Suspense React の新機能で、ページの一部を即時にレンダリングし、データをフェッチしているページの一部にローディング状態を表示します。

Building Your Application: Routing | Next.js