Lesson 7

動的なルーティングの実装方法

Lesson 7 Chapter 1
基礎知識

動的なルーティング(ダイナミックルーティンング)とは

本レッスンではNext.jsの動的なルーティングについて学んでいきます。 Next.js では、pages/books/[id].jsx のようなファイル名でページを作成すると、1 つのファイルで、
・/books/001
・/books/002
・/books/003
のようなパス (URL) によるアクセスを制御できます。
これを ダイナミックルーティング (Dynamic Routes) 機能と呼びます。
Next.js のページコンポーネント (/pages/xxx.jsx) は、そのページのルートコンポーネントとなるため、 通常の React コンポーネントとは違って、上位のコンポーネントから props 情報を渡すことができません。 そこで Next.js では、ページコンポーネントの実装ファイル内で getStaticProps 関数を定義することで、 ページコンポーネントに渡す props 情報を生成できるようにしています。
getStaticProps 内では、上記のような URL パラメータ情報(/books/[id] の id の部分の値)を取り出して、それを元に props 情報を生成できます。 この仕組みによって、Next.js のページコンポーネントは、1 つの .jsx ファイルで、複数のページ (.html) を生成できるようになっています。

getStaticPathsとは

SSGを用いてダイナミックルーティングを行う場合、あらかじめどのようなパラメーター(上記の例では id)でのアクセスが行われるかを把握した上で、各ページの内容を生成する必要があります。
これを実現するには、ページコンポーネントの実装ファイル (pages/*.jsx) で、getStaticPaths関数と前レッスンで学習したgetStaticPropsを実装して export します。

getStaticPaths関数

URL のパラメーター部分(上記の例では id)で指定可能な値を返すように設定します。 この関数は通常、Web サイトのビルド時にだけ実行されます。
次の例ではgetStaticPaths関数で/books/001、/books/002、/books/003 といった URL でアクセス可能な books/[id] ページを定義しています。

pages/books/[id].jsx
const getStaticPaths = async () => {
  return {
    paths: [
      {
        id: '001',
        id: '002',
        id: '003' 
      }
    ],
    fallback: false  // 上記以外のパスでアクセスした場合は 404 ページにする
  }
}

上記の様にあらかじめアクセスが想定されるパラメータを定義し、それ以外はfallbackプロパティでfalseを設定し404を返却する使用方法が一般的です。
またブログ等の記事更新等でパラメータのリストが動的に変わっていく場合、そのパラメータリストをfetch関数を使用して他APIサーバから取得することも可能です。
次のチャプターではgetStaticPaths関数と前レッスンで学習したgetStaticProps関数を使用して実際に動的なルーティングを実装していきましょう。

Lesson 7 Chapter 2
動的なルーティングの実装

getStaticPathsの実装

それでは実際に動的なルーティングを実装していきましょう。
データの取得先については前レッスン同様「JSONPlaceholder」を利用します。 取得したデータのID別にページをビルドし、内容としてタイトルと本文を表示させます。 Next.jsでは、pages内でファイル名に[]を使用することで自動的にダイナミックルーティングの対象となるので ファイル名はpages/dynamic/[id].jsxとし新規作成します。
ここでもう一度おさらいです。
ダイナミックルーティング用のファイルでは、getStaticPathsとgetStaticPropsの関数が必要です。

  • getStaticPaths:ビルド時にレンダリングする必要のあるパスのリストを生成する
  • getStaticProps:ビルド時に静的なファイルを生成し、ページコンポーネントで使用する値を用意する

  • ※ これらの関数は前レッスンのSSGにあたり、クライアント側での実行でなく、必ずサーバーサイドで実行されます。

    それではgetStaticPathsから実装していきます。
    pages/dynamic/[id].jsx
    const Dynamic = ({ post }) => {
        return (
            <div>
                <h1>{post.title}</h1>
                <p>{post.body}</p>
            </div>
        );
    };
    
    export const getStaticPaths = async () => {
        // JSONPlaceholderAPIと接続しデータ取得
        const res = await fetch("https://jsonplaceholder.typicode.com/posts");
        const posts = await res.json();
    
        const paths = posts.map((post) => ({
            params: {
                id: post.id.toString(),
            },
        }));
        return { paths, fallback: false };
    };
    
    export default Dynamic;

    上記でビルドする対象のリストパラメータ「paths」が作成できました。 pathsは事前ビルドするパス対象を指定する専用のパラメータです。データ取得先と型を揃えることに注意しましょう。 又、fallbackをfalseで事前ビルドしたパス以外にアクセスしたとき 404pageを表示をするようにgetStaticProps関数に渡していきます。

    getStaticPropsの実装

    それでは作成したpathsをgetStaticProps関数に渡してページをビルドするように実装していきます。

    pages/dynamic/[id].jsx
    const Dynamic = ({ post }) => {
        return (
            <div>
                <h1>{post.title}</h1>
                <p>{post.body}</p>
            </div>
        );
    };
    
    export const getStaticPaths = async () => {
        const res = await fetch("https://jsonplaceholder.typicode.com/posts");
        const posts = await res.json();
    
        const paths = posts.map((post) => ({
            params: {
                id: post.id.toString(),
            },
        }));
        return { paths, fallback: false };
    };
    
    export const getStaticProps = async ({ params }) => {
        const res = await fetch(
            `https://jsonplaceholder.typicode.com/posts/${params.id}`
        );
        const post = await res.json();
    
        return {
            props: {
                post,
            },
        };
    };
    
    export default Dynamic;

    画面表示までの流れ

    ・getStaticPathsで、レンダリングする必要のあるパスのリストを生成する
    ・getStaticPropsで、1で生成したパスのリストから1postずつAPIを呼び出しデータを取得する
    ・ページコンポーネントがgetStaticPropsからデータを受け取り、画面に表示される

    上記の様な流れになります。

    動作確認

    それでは動作確認していきます。
    ターミナルでnpm run buildを実行します。
    上記のコマンドでビルドが実行され、sample-app/.next/server/pages/dynamic配下に
    以下の画像の様に1.html,1.json,2.html,2.json... 100.jsonまでファイルが生成されていることを確認しましょう。

    nextjs-7-1

    上記の様になっていれば、SSGのファイルの生成は問題ありません。 実際にページの中身もみていきます。 生成されたファイルの1.htmlをブラウザで開いてみてください。 下記のようにタイトルと本文の内容が、JSONPlaceHolderのid:1の内容と同じであれば動的なルーティングの実装が完了です。

    nextjs-7-2 SSGで生成されたページ(1.html)1.html> nextjs-7-3 https://jsonplaceholder.typicode.com/posts/11.html>