2023年07月11日
さて、前回はブログの一覧がちゃんと取れることを確認しました。
続いて、一覧を気持ちよく表示できるようにしてしまいましょう。
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はここまでです。
ありがとうございました。