Nextjs の App Route の Dynamic Route を利用してブログのページを作る(後編)

公開日 :

前回、ブログの個別のページに関して、Dynamic Route で ID を利用して作成する手順を紹介しました。今回はもう1つ改善して、URL のパスに日付と Slug を利用して処理できるように進めていきます。

コンテンツタイプの拡張

Content Hub ONE で管理する項目に Slug を追加したいと思います。ブログの URL に関して、 /blog/slug とすることでランダムな ID ではなく意味のある URL とし、キーワードを入れて運用するためです。Content Hub ONE の Blog のコンテンツタイプを開いて、以下のように Slug を追加します。この項目は必須項目としました。

random desc

続いて既存のコンテンツに対して、Slug の項目が空欄になっている部分を入力して、Content Hub ONE 側の作業を完了させます。

Interface の変更

今回はデータの構造が変わったため、ブログに関しての型定義およびクエリを管理してている interfaces/blog/index.ts のコードを書き換えます。以下のコードのように slug を追加します。

export interface Blog {
  id: string;
  name: string;
  title: string;
  description: string;
  publishDate: string;
  slug: string;
  blogImage: {
    results: Partial<Media>[];
  };
}

また関連するクエリにも slug を追加してください。変更後、app/blog/[slug]/page.tsx のファイルでのデータを記述している部分を以下のように書き換えます。

  return (
    <div>
      {post.title} :{post.publishDate} {post.slug}
    </div>
  );

実際に publishDate および slug が表示されます。

random desc

また、api/queries/getBlog/index.tsx でも取得したデータの処理をしています。以下の参考コードの slug の行を追加してください。

      title: post.title,
      slug: post.slug,
      publishDate: post.publishDate,

URL に必要なデータを取得できているのを確認しました。

ID から Slug に切り替える

URL として利用していた値を ID から Slug の値に変更をします。まず、Slug を利用してブログの記事を表示するために、クエリを以下のように変更します。

export const getBlogSlugQuery = (slug: string) => {
  return `query AllBlog {
    allBlog(where: {slug_eq: "${slug}"}) {
      total
      results {
        description
        id
        name
        publishDate
        slug
        title
        blogImage {
          total
          results {
            id
            name
            description
            fileHeight
            fileId
            fileName
            fileSize
            fileType
            fileUrl
            fileWidth
          }
        }
      }
    }
  }
  `;
};

上記のクエリは全てのブログの記事から Slug の値が同じものを取得する形です。このため Slug にはユニークな値を設定してください。続いて記事を取得する関数を定義している、api/queries/getBlog/index.tsx に、以下のコードを追加してください。

export async function getBlogBySlug(slug: string): Promise<Partial<Blog>> {
  const results: AllBlogResponse = (await fetchGraphQL(
    getBlogSlugQuery(slug)
  )) as AllBlogResponse;

  return results.data.allBlog.results[0];
}

なお、クエリの名前が変わっているため import で記載するクエリの名前を getBlogSlugQuery に変更してください。これで Slug を利用して該当する記事を取得することが可能となります。

では実際に slug を URL で利用するために、 app/blog/[slug]/page.tsx のファイルにてgenerateStaticParams の記述にある slug に与えている post.id を post.slug に変更してください。

export async function generateStaticParams() {
  const posts = await getAllBlog();

  return posts.map((post) => ({
    slug: post.slug,
  }));
}

またページで取得するコンテンツを以下のように変更します。

  const post = await getBlogBySlug(params.slug);

これで Slug の値を利用してページを表示します。テストをしやすいように、トップページのapp/page.tsx のファイルの出力部分も以下のように変更します。

      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            <a href={"/blog/" + post.slug}>
              {post.title} {post.slug}
            </a>
          </li>
        ))}
      </ul>

実行をすると、以下のように slug を利用してブログのページが表示されていることがわかります。

random desc

まとめ

今回は Slug として利用するフィールドを追加して URL に関して制御できるようにする手順を紹介しました。表示しているコンテンツは title だけですが、データとしては取得できているので、あとはブログのページを作ったりしていく形です。