Next.jsでgetStaticPropsを使った静的データ生成完全ガイド

Next.jsは、Reactをベースにしたフレームワークであり、効率的な静的サイト生成(SSG)を可能にする機能を備えています。その中でも特に注目されているのが、getStaticPropsというメソッドです。このメソッドを活用することで、ビルド時にデータを取得し、静的に生成することで、ページの読み込み速度を大幅に向上させることができます。本記事では、getStaticPropsの基本的な仕組みや利点、実際の実装方法について解説します。React開発者がNext.jsを最大限に活用し、高パフォーマンスなウェブアプリケーションを構築するための重要な知識を習得する手助けとなる内容です。

目次

getStaticPropsとは何か


getStaticPropsは、Next.jsが提供する特殊な関数であり、ビルド時にデータを取得し、静的に生成されたHTMLファイルにデータを埋め込むために使用されます。この関数は、主に静的サイト生成(SSG)を目的としており、動的なデータを持つページを、高速でSEOに優れた形で提供することを可能にします。

仕組みの概要


getStaticPropsは、Next.jsがプロジェクトをビルドする際に実行されます。このときに外部APIやデータベース、ファイルシステムからデータを取得し、その結果を静的なHTMLに注入します。これにより、ページの表示速度を大幅に向上させることができます。

特長と制約

  • 特長
  • データはビルド時に一度だけ取得されるため、ユーザーがページにアクセスするたびにデータフェッチが発生しません。
  • 静的に生成されたページはキャッシュが容易で、パフォーマンスが向上します。
  • サーバーレス環境で動作するため、専用のサーバーが不要です。
  • 制約
  • ビルド時にデータが確定している必要があるため、リアルタイム性の高いデータには向きません。
  • ビルドプロセスが重くなる場合があります(特に大規模なデータセットの場合)。

適用されるケース


getStaticPropsは、以下のようなケースで特に有効です:

  • ブログやニュース記事の一覧表示
  • 商品一覧ページなど更新頻度が低いコンテンツ
  • 外部APIから取得した固定的なデータを含むページ

これにより、ユーザー体験を損なうことなく、Reactアプリケーションのパフォーマンスを最大限に引き出せます。

静的データ生成のメリット

静的データ生成(SSG)を活用することで、Next.jsはウェブページのパフォーマンスと効率性を大幅に向上させます。このセクションでは、静的データ生成の具体的なメリットを解説します。

パフォーマンスの向上


静的データ生成では、HTMLファイルがビルド時にあらかじめ生成されるため、サーバーからユーザーへのレスポンスが非常に高速です。この仕組みによって、以下のようなパフォーマンス向上が期待できます:

  • ユーザーがアクセスした際、バックエンドへのリクエストを減らせる。
  • ページが即座にレンダリングされ、初回描画時間(Time to First Byte, TTFB)が短縮される。

SEO(検索エンジン最適化)の向上


静的に生成されたページはHTMLが完全な状態で検索エンジンに提供されます。これにより、次のようなSEO上の利点があります:

  • 検索エンジンのクロールが容易になる。
  • JavaScriptのレンダリングを待たずに、検索エンジンがコンテンツを正確にインデックス化できる。

サーバーリソースの節約


静的データ生成はサーバーレス環境やCDNとの親和性が高く、以下のようなコスト削減を可能にします:

  • ページがキャッシュされることで、同時接続数の増加にも耐えられる。
  • サーバーサイドレンダリング(SSR)と比較して、サーバーの負荷が軽減される。

安定性と信頼性の向上


静的データ生成により、以下のような安定性の向上が見込まれます:

  • 依存するバックエンドの可用性に左右されにくい。
  • ユーザーが増加しても、静的ファイルはそのまま提供できるため、サービス停止のリスクを最小化できる。

応用例


静的データ生成は、以下のような状況で特に効果を発揮します:

  • 大規模な商品カタログを表示するECサイト。
  • 定期的に更新されるが、即時性が不要なブログやポートフォリオサイト。
  • 高トラフィックを見込むランディングページ。

これらのメリットを活用することで、静的データ生成は効率的でスケーラブルなウェブアプリケーション開発を実現します。

getStaticPropsの基本的な使用方法

getStaticPropsを活用することで、Next.jsではビルド時にデータを取得して静的なHTMLページを生成できます。ここでは、その基本的な使用方法を具体的なコード例とともに解説します。

基本構文


getStaticPropsは、Next.jsのページコンポーネント内でエクスポートされる非同期関数です。この関数が返すデータが、該当ページのプロパティとして渡されます。

export async function getStaticProps() {
  // データを取得
  const data = await fetch('https://api.example.com/data').then(res => res.json());

  // propsとしてページに渡す
  return {
    props: {
      data,
    },
  };
}

利用方法の手順

1. 必要なデータを取得


getStaticProps内で、外部APIやデータベースから必要なデータをフェッチします。上記コード例では、fetchを利用してAPIからデータを取得しています。

2. データを`props`として返す


取得したデータをpropsとして返すことで、ページコンポーネントで利用可能になります。

export default function Page({ data }) {
  return (
    <div>
      <h1>データ一覧</h1>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

注意点

データ取得に失敗した場合


APIがエラーを返した場合などに備えて、適切なエラーハンドリングを実装することが重要です。

export async function getStaticProps() {
  try {
    const data = await fetch('https://api.example.com/data').then(res => res.json());
    return { props: { data } };
  } catch (error) {
    console.error(error);
    return { props: { data: [] } }; // エラー時は空データを返す
  }
}

再ビルドの必要性


getStaticPropsで生成されたデータはビルド時に確定するため、データの更新には再ビルドが必要です。リアルタイム性が求められる場合はISR(Incremental Static Regeneration)の活用を検討してください。

結論


getStaticPropsは、静的データ生成を可能にする強力なツールです。シンプルな構文と柔軟なデータ取得方法を組み合わせることで、スケーラブルかつ高速なウェブページを簡単に作成できます。

データフェッチと外部APIとの連携

Next.jsのgetStaticPropsを活用すれば、外部APIやサードパーティサービスと連携し、動的なデータを静的に生成することが可能です。このセクションでは、外部APIからデータを取得する方法と、それを静的データとして活用する手順を解説します。

外部APIを利用したデータフェッチ


getStaticProps内で外部APIと連携し、必要なデータを取得します。以下はその基本例です。

export async function getStaticProps() {
  const apiUrl = 'https://api.example.com/items'; // 外部APIのエンドポイント
  const response = await fetch(apiUrl); // APIにリクエスト
  const data = await response.json(); // JSON形式でデータを取得

  return {
    props: {
      items: data, // ページに渡すデータ
    },
  };
}

ページでのデータ活用


取得したデータはpropsを通じてページコンポーネントに渡されます。以下の例は、取得したデータをリストとして表示するコードです。

export default function ItemsPage({ items }) {
  return (
    <div>
      <h1>アイテム一覧</h1>
      <ul>
        {items.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

API連携の応用例

複数APIの統合


複数のAPIからデータを取得して統合する場合も、同じ構造を利用できます。

export async function getStaticProps() {
  const [usersRes, postsRes] = await Promise.all([
    fetch('https://api.example.com/users'),
    fetch('https://api.example.com/posts'),
  ]);

  const [users, posts] = await Promise.all([usersRes.json(), postsRes.json()]);

  return {
    props: {
      users,
      posts,
    },
  };
}

認証が必要なAPIの利用


認証トークンが必要なAPIの場合、fetchリクエストにヘッダーを追加します。

export async function getStaticProps() {
  const token = 'your-auth-token'; // トークンを用意
  const response = await fetch('https://api.example.com/protected-data', {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });
  const data = await response.json();

  return {
    props: {
      data,
    },
  };
}

注意点とベストプラクティス

APIのエラーハンドリング


外部APIが応答しない場合やエラーを返した場合に備え、適切なエラーハンドリングを実装することが重要です。

export async function getStaticProps() {
  try {
    const response = await fetch('https://api.example.com/items');
    if (!response.ok) {
      throw new Error('APIエラー');
    }
    const data = await response.json();
    return { props: { items: data } };
  } catch (error) {
    console.error(error);
    return { props: { items: [] } }; // エラー時は空データ
  }
}

APIレート制限への配慮


ビルド時に大量のリクエストを送信することでAPIのレート制限に引っかかる可能性があります。この問題を回避するには、APIレスポンスのキャッシュやローカルファイルの利用を検討してください。

結論


getStaticPropsを用いた外部APIとの連携は、動的データを静的ページに取り込む非常に有効な手段です。適切な設計とエラーハンドリングを組み合わせることで、信頼性が高く高速なウェブアプリケーションを構築できます。

getStaticPropsとISR(Incremental Static Regeneration)

Next.jsは、getStaticPropsとISR(Incremental Static Regeneration)を組み合わせることで、静的データ生成の強力な機能を提供します。このセクションでは、ISRの基本的な仕組みとgetStaticPropsとの統合方法について解説します。

ISRとは何か


ISRは、Next.jsが提供する機能で、静的サイト生成(SSG)の柔軟性をさらに高めるものです。特定のページを定期的に再生成することで、以下を可能にします:

  • 静的ページの更新をリアルタイムに近い形で実現する。
  • ビルドプロセス全体を繰り返すことなく、新しいデータを反映する。

ISRの仕組み


ISRを利用すると、ページごとに再生成の間隔(リビルド間隔)を設定できます。この設定は、getStaticPropsでrevalidateプロパティを指定することで行います。

基本的なコード例


以下の例では、ページが10秒ごとに再生成されます。

export async function getStaticProps() {
  const data = await fetch('https://api.example.com/data').then(res => res.json());

  return {
    props: {
      data,
    },
    revalidate: 10, // 10秒ごとに再生成
  };
}

仕組みの流れ

  1. ユーザーがページに初回アクセスすると、ビルド時に生成された静的HTMLが表示されます。
  2. revalidateの期間が経過すると、次回アクセス時にサーバー上でページが再生成されます。
  3. 再生成されたページは、以降のリクエストに対して配信されます。

ISRと`getStaticProps`の連携例

ブログの例


ブログの投稿一覧ページを、10分ごとに再生成する設定をした例を以下に示します。

export async function getStaticProps() {
  const posts = await fetch('https://api.example.com/posts').then(res => res.json());

  return {
    props: {
      posts,
    },
    revalidate: 600, // 600秒(10分)
  };
}

ページコンポーネントでは、取得したデータを表示します。

export default function Blog({ posts }) {
  return (
    <div>
      <h1>最新のブログ投稿</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.body}</p>
        </article>
      ))}
    </div>
  );
}

メリットと制約

メリット

  • 動的更新:データが変更されても、定期的な再生成によって最新の情報が反映される。
  • パフォーマンス:静的ページとして提供されるため、読み込み速度が速い。
  • スケーラビリティ:多くのトラフィックに対応可能。

制約

  • リビルド間隔のタイミング:リアルタイム性は完全には実現できない。
  • 初回リクエストの遅延:再生成中の最初のリクエストが遅れる可能性がある。

注意点とベストプラクティス

リビルド間隔の適切な設定


頻繁に更新されるデータには短い間隔を設定し、ほとんど変わらないデータには長めの間隔を設定することで効率的な運用が可能です。

エラーハンドリング


再生成中にAPIエラーが発生した場合に備え、fallbackデータやエラー表示を実装しておくと、ユーザー体験を損なわずに対応できます。

結論


getStaticPropsとISRの組み合わせは、静的生成のスピードと動的更新の柔軟性を兼ね備えています。この手法を活用することで、高速で信頼性の高いウェブアプリケーションを効率的に構築できます。

エラーハンドリングのベストプラクティス

getStaticPropsを使用する際に、データ取得中のエラーを適切に処理することは重要です。外部APIの応答遅延やサーバーエラー、ネットワーク問題など、様々な要因でエラーが発生する可能性があります。本セクションでは、エラーハンドリングのベストプラクティスを具体例とともに解説します。

基本的なエラーハンドリング

getStaticProps内で発生するエラーをキャッチして適切に対処することで、ページがクラッシュするのを防ぎます。

例: シンプルなエラーハンドリング

export async function getStaticProps() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) {
      throw new Error(`HTTPエラー: ${response.status}`);
    }
    const data = await response.json();

    return {
      props: { data },
    };
  } catch (error) {
    console.error('データ取得エラー:', error);
    return {
      props: { data: null }, // エラー時はnullを返す
    };
  }
}

このようにすることで、エラー発生時にもアプリケーション全体が停止するのを防ぎます。

エラー時のユーザー向けメッセージ

取得したデータがnullの場合、エラーメッセージを表示するなど、ユーザー体験を損なわない工夫が必要です。

export default function Page({ data }) {
  if (!data) {
    return <p>データの取得に失敗しました。再試行してください。</p>;
  }

  return (
    <div>
      <h1>データ一覧</h1>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

外部APIの代替データを用意する

外部APIが利用できない場合でも、アプリケーションが完全に機能しないのを防ぐために、代替データを用意することが推奨されます。

const fallbackData = [
  { id: 1, name: 'Fallback Item 1' },
  { id: 2, name: 'Fallback Item 2' },
];

export async function getStaticProps() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('APIエラー');
    const data = await response.json();

    return {
      props: { data },
    };
  } catch {
    console.warn('API利用不可: 代替データを使用します');
    return {
      props: { data: fallbackData },
    };
  }
}

再生成時のエラーハンドリング(ISR)

ISR(Incremental Static Regeneration)を利用する場合、再生成中にエラーが発生しても、既存のページがそのまま表示されるため、ユーザーへの影響を最小限に抑えられます。エラー時のログを記録することで問題のトラブルシューティングを容易にします。

export async function getStaticProps() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();

    return {
      props: { data },
      revalidate: 10, // 再生成間隔
    };
  } catch (error) {
    console.error('ISR再生成エラー:', error);
    return {
      props: { data: null },
      revalidate: 10, // 再生成試行は続行
    };
  }
}

エラーハンドリングのポイント

  1. エラーログの記録:開発中のデバッグや本番環境でのモニタリングに役立てます。
  2. 代替データの準備:ユーザー体験を損なわない設計。
  3. ユーザーフィードバックの提供:エラー発生時は、再試行や問い合わせの指示を明確に伝える。
  4. 再生成プロセスの保護:ISRで既存ページが壊れないようにする。

結論


getStaticPropsでのエラーハンドリングは、Next.jsアプリケーションの信頼性を向上させる鍵となります。適切な対処法を実装することで、ユーザー体験を維持しつつ、開発効率を高めることができます。

実用的な応用例:ブログサイトの構築

getStaticPropsを活用すれば、動的なデータを用いたブログサイトを静的に生成することが可能です。このセクションでは、ブログ記事をAPIから取得し、一覧ページや詳細ページを静的に生成する具体的な方法を紹介します。

ブログ記事の一覧ページの構築

ブログ記事のデータを外部APIから取得し、静的な一覧ページを作成します。

データ取得と静的生成


以下は、ブログ記事を取得して静的に生成するためのコード例です。

export async function getStaticProps() {
  const response = await fetch('https://api.example.com/posts');
  const posts = await response.json();

  return {
    props: { posts },
  };
}

export default function BlogList({ posts }) {
  return (
    <div>
      <h1>ブログ記事一覧</h1>
      {posts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.summary}</p>
          <a href={`/posts/${post.id}`}>続きを読む</a>
        </div>
      ))}
    </div>
  );
}
  • 外部APIから記事データを取得し、propsとして渡します。
  • ページコンポーネント内でprops.postsを利用して記事一覧を表示します。

ブログ記事の詳細ページの構築

個々のブログ記事の詳細ページを生成するには、getStaticPathsを併用します。

動的ルートの設定とデータ取得


以下は、記事詳細ページを静的に生成するためのコード例です。

export async function getStaticPaths() {
  const response = await fetch('https://api.example.com/posts');
  const posts = await response.json();

  const paths = posts.map(post => ({
    params: { id: post.id.toString() }, // 動的ルートのパスを生成
  }));

  return { paths, fallback: false }; // すべてのページをビルド
}

export async function getStaticProps({ params }) {
  const response = await fetch(`https://api.example.com/posts/${params.id}`);
  const post = await response.json();

  return {
    props: { post },
  };
}

export default function PostDetail({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}
  • getStaticPathsで、すべての記事IDを取得し、それぞれの詳細ページを生成します。
  • getStaticPropsを使って、各記事の詳細データを取得します。

応用例:検索機能とフィルタリング

記事一覧ページに検索機能やカテゴリフィルタを追加することで、ユーザー体験を向上させることができます。

import { useState } from 'react';

export default function BlogList({ posts }) {
  const [search, setSearch] = useState('');
  const filteredPosts = posts.filter(post =>
    post.title.toLowerCase().includes(search.toLowerCase())
  );

  return (
    <div>
      <h1>ブログ記事一覧</h1>
      <input
        type="text"
        placeholder="検索"
        value={search}
        onChange={e => setSearch(e.target.value)}
      />
      {filteredPosts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.summary}</p>
          <a href={`/posts/${post.id}`}>続きを読む</a>
        </div>
      ))}
    </div>
  );
}
  • 検索バーを追加し、ユーザーがリアルタイムで記事を絞り込めるようにします。
  • フィルタリングロジックはクライアントサイドで実行されるため、即時性が高いです。

デザインとパフォーマンスの最適化

  • CSSフレームワーク:Tailwind CSSやBootstrapを使用して、記事一覧と詳細ページのデザインを強化します。
  • 画像の最適化:Next.jsのImageコンポーネントを使い、画像を自動的に最適化します。

結論


getStaticPropsとgetStaticPathsを活用することで、APIを基盤にした静的なブログサイトを簡単に構築できます。検索機能やデザインの最適化を組み合わせることで、機能性とユーザー体験をさらに向上させることが可能です。

コードスプリットとパフォーマンス最適化

Next.jsでは、getStaticPropsを活用した静的データ生成だけでなく、コードスプリットによるパフォーマンス最適化が可能です。このセクションでは、コードスプリットの基本概念と、getStaticPropsとの連携による効果的な最適化手法を解説します。

コードスプリットとは

コードスプリットは、アプリケーションのJavaScriptコードを必要最小限に分割して配信する技術です。これにより、初期ロード時間が短縮され、ユーザーエクスペリエンスが向上します。Next.jsはデフォルトでコードスプリットをサポートしていますが、さらなる最適化も可能です。

動的インポートによるコードスプリット

特定のコンポーネントや機能を動的に読み込むことで、初期ロード時のJavaScriptサイズを削減できます。

例: 動的インポートの実装

import dynamic from 'next/dynamic';

const HeavyComponent = dynamic(() => import('../components/HeavyComponent'), {
  ssr: false, // サーバーサイドレンダリングを無効化
});

export default function Page() {
  return (
    <div>
      <h1>パフォーマンス最適化</h1>
      <HeavyComponent />
    </div>
  );
}
  • dynamic関数を使って、必要なタイミングでコンポーネントを読み込みます。
  • 必要に応じてssr: falseを設定し、クライアントサイドでのみレンダリングされるようにします。

`getStaticProps`との連携

getStaticPropsで取得したデータを元に、動的インポートを活用することで効率的にページを構成できます。

例: APIデータに基づく動的レンダリング

import dynamic from 'next/dynamic';

const DynamicComponent = dynamic(() => import('../components/DynamicComponent'));

export async function getStaticProps() {
  const data = await fetch('https://api.example.com/data').then(res => res.json());

  return {
    props: { data },
  };
}

export default function Page({ data }) {
  return (
    <div>
      <h1>データに基づくコンポーネント</h1>
      {data.map(item => (
        <DynamicComponent key={item.id} item={item} />
      ))}
    </div>
  );
}
  • getStaticPropsで取得したデータを基に、動的にコンポーネントをレンダリングします。
  • 必要に応じてコンポーネントを動的にインポートし、効率的なパフォーマンスを実現します。

画像の最適化

Next.jsのImageコンポーネントを活用すると、画像を自動的に最適化できます。これにより、ページの読み込み速度を向上させることが可能です。

import Image from 'next/image';

export default function Page() {
  return (
    <div>
      <h1>画像最適化</h1>
      <Image
        src="/example.jpg"
        alt="サンプル画像"
        width={600}
        height={400}
        quality={75} // 画像クオリティを指定
      />
    </div>
  );
}

ビルド時のパフォーマンス改善

依存ライブラリの軽量化


使用しているサードパーティライブラリを見直し、軽量な代替ライブラリを選択することで、ビルドサイズを削減できます。

アンチパターンの回避

  • 全ページで使用しないライブラリを_app.jsでインポートしない。
  • 不要なコードやコンポーネントを削除して、ビルドプロセスを最適化する。

応用例: ランディングページの高速化

ランディングページでは、以下の手法を組み合わせて高速化を図ります:

  1. 初期レンダリング時に必要なコンテンツだけを表示。
  2. サブページやリッチコンテンツを動的インポート。
  3. 画像とフォントの最適化。

結論

コードスプリットとgetStaticPropsを組み合わせることで、Next.jsアプリケーションのパフォーマンスを飛躍的に向上させることが可能です。適切な設計と実装を行うことで、スピーディかつユーザー体験を損なわないウェブアプリケーションを構築できます。

まとめ

本記事では、Next.jsのgetStaticPropsを活用した静的データ生成について詳しく解説しました。基本的な使い方から、ISRや外部APIとの連携、エラーハンドリング、さらにはパフォーマンスを最適化するためのコードスプリットや応用例まで網羅しました。

getStaticPropsを適切に活用することで、静的なページの高速性と動的データの柔軟性を両立することが可能です。また、ISRを組み合わせることで、リアルタイム性の高いアプリケーションにも対応できます。

これらの知識を応用し、SEOやユーザー体験に優れたウェブアプリケーションを構築してください。Next.jsの強力な機能を活用することで、パフォーマンス、効率、信頼性に優れたウェブプロジェクトが実現します。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次