Next.js ハンズオン-その1: 掲示板機能
はじめに
この記事はNext.jsで掲示板を作るもっとも簡単な例を解説します。
全体の流れ
- npxでNext.jsアプリを作成。
- APIを作成し、記事データを提供するエンドポイントを作成。
- トップページでAPIを使って記事一覧を表示。
- 動的ルーティングを使用して記事の詳細ページを作成。
- CSSで全体のスタイリングを整える。
Step0: Next.jsアプリの作成
以下のコマンドでNext.jsアプリを作成しましょう。
TypeScriptとappディレクトリを選んでおくと良いです。(基本的にEnterを押し続けておけばよいです。)
$ npx create-next-app@latest blog-app
アプリのひな型ができたら開発サーバーを起動しましょう。
$ cd blog-app
$ npm run dev
開発サーバーが起動し、http://localhost:3000でアプリが確認できます。
Step1: APIをNext.js内で作成
app/api/posts/route.ts
記事データを提供するAPIエンドポイントを作成します。appディレクトリ内にapiフォルダを作成し、その中にroute.tsファイルを追加します。
appルーティングにおけるapiフォルダの取り扱いはこちら
import { NextResponse } from 'next/server';
const posts = [
{ id: 1, title: 'First Post', body: 'This is the first post.' },
{ id: 2, title: 'Second Post', body: 'This is the second post.' },
{ id: 3, title: 'Third Post', body: 'This is the third post.' },
];
export async function GET() {
return NextResponse.json(posts);
}
・/api/postsエンドポイントが作成され、GET(つまりhttp://localhost:3000/api/postsへのアクセス)によって記事データの配列が返されるようにしました。
・実際にはこの部分でデータベースや他のAPIからデータを取得することも可能です。
Step 2: トップページの作成
app/page.tsx
APIから記事データを取得して、一覧表示するトップページを作成します。
import Link from 'next/link';
async function getPosts() {
const res = await fetch('http://localhost:3000/api/posts');
if (!res.ok) {
throw new Error('Failed to fetch posts');
}
return res.json();
}
export default async function HomePage() {
const posts = await getPosts();
return (
<div>
<h1>Blog Posts</h1>
<ul>
{posts.map((post: { id: number; title: string }) => (
<li key={post.id}>
<Link href={`/posts/${post.id}`}>
{post.title}
</Link>
</li>
))}
</ul>
</div>
);
}
・fetch関数を使って、/api/postsエンドポイントから記事データを取得し、記事のタイトルを表示します。
・Linkコンポーネントで、記事詳細ページへのリンクを作成しています。
map()が分からない方へ
- posts配列の各要素(記事データ)に対してmap()を実行し、各記事に対応するリストアイテム<li>を生成します。
- それぞれの<li>に記事のタイトルを表示し、リンクとしてクリック可能にします。
- リンクをクリックすると、/posts/に続く記事IDのパスに動的に遷移し、該当する記事の詳細ページが表示されます
Step 3: 動的なルーティングによる記事詳細ページの作成
app/posts/[id]/page.tsx
動的ルーティングを使用して記事の詳細ページを作成します。
import { notFound } from 'next/navigation';
async function getPost(id: string) {
const res = await fetch(`http://localhost:3000/api/posts`);
if (!res.ok) {
throw new Error('Failed to fetch posts');
}
const posts = await res.json();
return posts.find((post: { id: number }) => post.id.toString() === id);
}
export default async function PostPage({ params }: { params: { id: string } }) {
const post = await getPost(params.id);
if (!post) {
notFound();
}
return (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
<Link href="/">Back to Home</Link>
</div>
);
}
・動的なルーティングを使用し、URLパラメータ(params.id)に基づいて、記事をフィルタリングして詳細ページを表示します。
・記事が見つからない場合、notFound()関数で404ページを表示します。
({ params }: { params: { id: string } })が分からない方へ
・関数の引数として、paramsというオブジェクトを受け取っています。これはNext.jsの動的ルーティングで自動的に渡されるもので、URLのパスパラメータ(ここではid)が含まれています。
・{ params }: { params: { id: string } }は、TypeScriptによる型定義です。これにより、paramsがidというキーを持つオブジェクトであり、idは文字列型であることが明示されています。
Step 4: スタイリングの追加
app/globals.css
基本的なスタイルを追加します。globals.cssはappディレクトリのルートに置き、全体のスタイリングに利用します。
/* app/globals.css */
body {
font-family: Arial, sans-serif;
padding: 20px;
margin: 0;
background-color: #f4f4f4;
}
h1 {
color: #333;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 10px 0;
}
a {
color: #0070f3;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
Discussion