👋

【Next.js】Next.js & Contentful BlogApp 【10PostDetailsPage1】

2022/11/26に公開約2,900字

【10PostDetailsPage1】

YouTube:https://youtu.be/TjhlQFDAxTU

https://youtu.be/TjhlQFDAxTU

今回は各ブログ記事の詳細ページの作成を行います。

まずはトップページのファイルに不要な部分がありますので、
そちらの削除から始めます。

「[slug].js」が作成できましたら、
「CardItem.js」に「Link」コンポーネントを追加して、
カードをクリックしたら、詳細ページに遷移できるようにします。

pages/index.js
import { useEffect, useState } from 'react'
import CardItem from '../components/CardItem'
import Hero from '../components/Hero'
import Layout from '../components/Layout'
import { client } from '../utils/contentfulClient'

export default function Home() {
  const [items, setItems] = useState([])

  useEffect(() => {
    ;(async () => {
      const res = await client.getEntries({
        content_type: 'myPosts',
      })
      setItems(res.items)
    })()
  }, [])

  return (
    <Layout>
      <Hero />
      <div className=" max-w-7xl flex flex-wrap justify-center mx-auto mb-3 py-2 gap-4">
        {items ? (
          items.map((item) => (
            <div key={item.sys.id}>
              <CardItem item={item} />
            </div>
          ))
        ) : (
          <div className=" text-center text-3xl font-black">No Posts...</div>
        )}
      </div>
    </Layout>
  )
}
pages/posts/[slug].js
import Image from 'next/image'
import Layout from '../../components/Layout'

const PostDetailsPage = () => {
  return (
    <Layout title="post-details">
      <div className="w-full">
        <div className="max-w-6xl flex flex-wrap justify-between items-center mx-auto py-6 px-5 gap-3">
          <div>
            <h1 className="font-bold text-3xl sm:text-4xl md:text-4xl lg:text-5xl py-3 mb-1">
              My Blog App
            </h1>
            <p className="font-bold text-2xl mb-2">Web Frontend & Backend</p>
          </div>
          <div>
            <Image
              src="/images/img_hero.png"
              alt="main_visual"
              width={500}
              height={500}
              className="rounded"
            />
          </div>
        </div>
      </div>
      <div className="max-w-6xl mx-auto p-5">blog text</div>
    </Layout>
  )
}

export default PostDetailsPage
components/CardItem.js
import Image from 'next/image'
import Link from 'next/link'

const CardItem = ({ item }) => {
  return (
    <Link href={`posts/${item.fields.slug}`}>
      <div className="w-96 md:w-64 lg:w-96 p-4 border border-solid border-slate-400 rounded-md bg-white">
        <div className="w-full h-64 relative mb-2 bg-orange-200">
          <Image
            src={`https:${item.fields.image.fields.file.url}`}
            alt={item.fields.image.fields.title}
            fill
            sizes="100%"
            className="object-cover"
          />
        </div>
        <h3 className="font-black text-xl sm:text-xl md:text-base lg:text-xl mb-1">
          {item.fields.title}
        </h3>
        <div>
          <span>{item.sys.createdAt.substring(0, 10)}</span>
        </div>
      </div>
    </Link>
  )
}

export default CardItem

Discussion

ログインするとコメントできます