tamakipedia

フロントエンドエンジニア。Typescriptもう特訓中です。一日の振り返りや学んだことをちょっとずつ吐いています。

【Next.js】【contentful】動的なルーティングを利用した詳細ページの作成

こんにちは、本日はcontentfulのエントリーの内容を詳細ページに追加していこうと思います。
なお、エントリーは一記事単位の呼び方です。
(下記図参照)

f:id:okinawanpizza:20211024201207p:plain

結果

以下が全体図です。

//pages/posts/[slug].js
import { createClient } from "contentful";
import Image from "next/image";
import { documentToReactComponents } from "@contentful/rich-text-react-renderer"

const client = createClient({
  space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID,
  accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN,
});

export const getStaticPaths = async () => {

  //article 全件取得
  const res = await client.getEntries({
    content_type: "article"
  })

  //全件のパラメーターだけを配列形式で取得
  //[ { params: { slug: 'test2' } }, { params: { slug: 'test1' } } ]
  const paths = res.items.map(item => {
    return {
      params: { slug: item.fields.slug }
    }
  })

  return {
    paths,
    fallback: false
  }
}

export async function getStaticProps({ params }) {
  
  const { items } = await client.getEntries({
    content_type: "article",
    "fields.slug": params.slug
  })

  return{
    props: { article: items[0] }
  }
}


export default function ArticleDetails({ article }) {
  const { thumbnail, Title, detail} = article.fields

  return (
    <div>
      //省略
    </div>
  );
};

Dynamic Routes(動的なルーティング)

Next.jsでは設定したファイル名が自動的にスラッグになります。
また[params].jsなどのようにしてファイル名に角括弧(ブラケット)を使うことで
動的なルーティングを作成できます。

つまり * pages/post/create.js/post/create にマッチします。 * pages/post/[sulg].js/post/1/post/abc にマッチします。

contentfulのインポート

contentfulをインポートします。

import { createClient } from "contentful";

spaceIDとaccessTokenを入力し
contentfulにアクセスするapiを取得します。

const client = createClient({
  space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID,
  accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN,
});

それぞれのエントリーのslug名を全件取得

content_typearticleのエントリー(記事)をjson形式で取得、
それぞれのslugと言う項目だけを返すようにします。
下記のような形が返却されます。
[ { params: { slug: 'test2' } }, { params: { slug: 'test1' } ,....} ]

  //article 全件取得
  const res = await client.getEntries({
    content_type: "article"
  })

  //全件のパラメーターだけを配列形式で取得
  //[ { params: { slug: 'test2' } }, { params: { slug: 'test1' } } ]
  const paths = res.items.map(item => {
    return {
      params: { slug: item.fields.slug }
    }
  })

  return {
    paths,
    fallback: false
  }

ちなみにslugのcontentful側での設定は
content model から手動で設定しているものになります。
f:id:okinawanpizza:20211024214937p:plain

urlに該当するエントリーを取得

現在のurlに該当するエントリーをgetEntries関数で取得し
コンポーネント側にpropsを渡します。

export async function getStaticProps({ params }) {
  
  const { items } = await client.getEntries({
    content_type: "article",
    "fields.slug": params.slug
  })

  return{
    props: { article: items[0] }
  }
}

export default function ArticleDetails({ article }) {
  console.log(article)

  return (
    <div>
      //省略
    </div>
  );
};

以上です!、、思ったより手こずりました。
ただ、youtubeで英語でガッツリ解説してくれている動画を見つけて
そこから意外とスムーズにいきました。

おしまい