Jamstackなブログを作ろう #2

2023年07月11日

Jamstackなブログを作ろう #2

さて、前回はブログの一覧がちゃんと取れることを確認しました。

続いて、一覧を気持ちよく表示できるようにしてしまいましょう。

CSSについては、すでに当ててしまった状態になっていますが、ご了承ください。

リスト表示コンポーネントを作ろう

ということで、ブログ一覧の部分です。

ブログ一覧の「記事一つ一つ」を表示するようにします。

この記事一つをコンポーネント化します。

ということで、app直下にcomponentsディレクトリを作成します。

その中に...今回はBlogListCard.tsxを作成します。

BlogListCard.tsxは以下のような内容です。

import Image from "next/image";
import Link from "next/link";
import { format } from "date-fns";
import styles from "../styles/page.module.css";

// TODO : thumnail & catedory
interface Props {
  id: string;
  title: string;
  thumnail: string;
  //   category: string;
  createAt: string;
  updatedAt: string;
}

const BlogListCard = ({
  id,
  title,
  thumnail,
  //   category,
  createAt,
  updatedAt,
}: Props) => {
  return (
    <>
      <div className={styles.blogCard}>
        <Link href={`/blog/${id}`}>
          <div className={styles.cardWrap}>
            <div className={styles.cardThumnail}>
              <Image src={thumnail} width={320} height={200} alt={title} />
            </div>
            <div className={styles.cardText}>
              <div>
                <h2 className={styles.cardTitle}>{title}</h2>
              </div>
              <div className={styles.createdate}>
                <h3>作成日 : {format(new Date(createAt), "yyyy-MM-dd")}</h3>
                <h3>更新日 : {format(new Date(updatedAt), "yyyy-MM-dd")}</h3>
              </div>
            </div>
          </div>
        </Link>
      </div>
    </>
  );
};

export default BlogListCard;

内容

interfaceは、型の指定になります。

現状、訳あってcategoryだけコメントアウトしてあります。後日実装予定です。

このコンポーネントを、Linkで囲みます。リンク先はブログの詳細です。そっちはまた後で実装します。

で、このコンポーネントには、以下の情報を表示します。

  • 記事のサムネイル
  • 記事のタイトル
  • 記事の作成日
  • 記事の更新日(これはいらないかも)

もちろん、皆さまの考えで、さらにカテゴリを表示したりするのも全然ありです。適当にカスタマイズしてみていただければと思います。

このコンポーネント自体は、正直中身も難しくないので、さらっと。

リストコンポーネントを呼び出そう

#1でもお伝えしましたが、私の場合、app以下のディレクトリ構造が以下のようになっています。

なお、app/blog/[id]については、今後作成しますので、今の時点では気にしないでください。

app
├── about
├── blog
│   └── [id]
├── components
└── styles

先ほどのBlogListCard.tsxはapp/componentsに作成しました。

続いては、app/blogにlayout.tsxを作成します。このlayout.tsxと対になるpage.tsxがあることで、/blogにアクセスした際に、正常に表示されるようになります。

import "../globals.css";
import { Inter } from "next/font/google";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function BlogListPage({
  children,
}: {
  children: React.ReactNode;
}) {
  return <div>{children}</div>;
}

基本的に、layout.tsxでは処理をしていません。

metadataが変なのは、後々修正しますので、お気になさらずに...。

続いて、対になるapp/blog/page.tsxです。

import Image from "next/image";
import { client, getBlogs } from "@/libs/microcms";
import { BlogPostType } from "@/types/blogPost";
import Link from "next/link";
import BlogListCard from "../components/BlogListCard";
import styles from "../styles/page.module.css";

import { M_PLUS_Rounded_1c } from "next/font/google";

const mPlus400 = M_PLUS_Rounded_1c({
  weight: ["400"],
  subsets: ["latin"],
  display: "swap",
});

export const revalidate = 0;

export default async function BlogList() {
  // const { contents } = await getBlogs();

  const contents = await getBlogs();
  // console.log(contents);
  return (
    // <main className="flex min-h-screen flex-col items-center justify-between p-24">
    // <main className="flex min-h-screen flex-col items-center p-24">
    <main
      className={`flex min-h-screen flex-col items-center p-24 ${styles.aboutMain}`}
    >
      <h2 className={styles.blogListTitle}>
        <span className={mPlus400.className}>記事一覧</span>
      </h2>
      <ul>
        {contents.map((postData: BlogPostType) => {
          return (
            <li key={postData.id} className={styles.blogListCard}>
              <BlogListCard
                key={postData.id}
                id={postData.id}
                title={postData.title}
                createAt={postData.createdAt}
                updatedAt={postData.updatedAt}
                thumnail={postData.eyecatch?.url || "/no-image.png"}
              />
            </li>
            // <Link key={postData.id} href={`/blog/${postData.id}`}>
            //   <li key={postData.id}>{postData.title}</li>
            // </Link>
          );
        })}
      </ul>
    </main>
  );
}

内容

まず、getBlogsでブログの一覧を取得します。これは#1にソースがあります。

取ってきたブログ一覧を、いつ戻りmapでぐるぐる回して、その一つ一つをBlogListCardに渡します。

これも、そんなに難しくないので、大丈夫かと思います。

thumnailの部分については、もし、eyecatchのurlに値が入っていればそれを使うけど、なかったらno-image.pngを使う、という記述です。

あれ?更新されない

あと、これが最適解かどうかわからないのですが、ブログ記事を公開した後、どれだけブログ一覧ページを更新しても、画面上に表示されませんでした。

ビルド後の.nextディレクトリを削除して再度ビルドすれば表示されるのですが、さすがにそれは違う気がします。

ということで、あちこち探し回りました。

結果、

export const revalidate = 0;

を追加することで、都度更新されるようになりました。

これでいいのかどうか、ちょっとわかってないのですが...お恥ずかしい限りです、はい。

ということで

一覧部分は、SSG以外はやっぱり難しくないですね。

ということで、#2はここまでです。

ありがとうございました。

戻る