🖥️
Next.js入門7 Todoアプリ(タスク詳細)
記事一覧
- Next.js × Docker 最速環境構築
- Next.js入門1 ページ追加
- Next.js入門2 コンポーネント
- Next.js入門3 無記名関数 & イベントハンドラー
- Next.js入門4 Hooks
- Next.js入門5 Todoアプリ(タスク一覧)
- Next.js入門6 Todoアプリ(タスク追加)
- Next.js入門7 Todoアプリ(タスク詳細)
- Next.js入門8 Todoアプリ(タスク編集, 削除)
動的ルーティング
動的ルーティングとは
URLの一部が変化するパターンに応じて異なるページやコンポーネントを表示する仕組み
タスク詳細
動的ルーティング(http://localhost:3000/task/タスク番号
)でアクセスできる詳細ページを作る
ページ作成
-
task/[index]/page.tsx
を作成
.
├── next-app
│ └── app
│ └── task
│ └── [index]
│ └── page.tsx # ここに作成
├── docker-compose.yml
└── Dockerfile
-
task/[index]/page.tsx
を記述
"use client";
// useは非同期処理を実行するためのHooks
import { use, useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Button } from "@/components/button";
import { Task } from "@/types/task";
type Props = {
// Promiseは非同期処理の結果を表す型
params: Promise<{
index: string; // urlの[index]
}>;
};
function Page({ params }: Props) {
// useを使用して非同期処理を実行し、結果を取得
// parseIntで文字列を数値に変換
const index = parseInt(use(params).index);
const router = useRouter();
const [task, setTask] = useState<Task>();
const [tasks, setTasks] = useState<Task[]>([]);
useEffect(() => {
// ローカルストレージからタスクを取得
const storedTasks = localStorage.getItem("tasks");
// タスクがある場合はタスクを設定
if (storedTasks) {
const parsedTasks = JSON.parse(storedTasks);
setTasks(parsedTasks); // 全体のタスクを設定
setTask(parsedTasks[index]); // 選択したタスクを設定
}
}, [index]); // indexが変更されたら実行
// タスクがない場合は何も表示しない
if (!task) {
return;
}
return (
<div className="flex flex-col gap-8 items-center p-16">
<h1 className="text-4xl font-bold">タスク詳細</h1>
<div className="w-full flex flex-col gap-8 border rounded-2xl p-8">
<div className="flex gap-2 border-b">
<label className="font-bold">タスク名</label>
<p>{task.title}</p>
</div>
<div className="flex flex-col gap-2">
<label className="font-bold border-b">内容</label>
<p>{task.content}</p>
</div>
</div>
<div className="w-full flex justify-between">
<Button
onClick={() => {
router.push("/task"); // タスク一覧に戻る処理
}}
>
戻る
</Button>
</div>
</div>
);
}
export default Page;
一覧ページ編集
-
components/table.tsx
を編集
// useRouterをインポート
import { useRouter } from "next/navigation";
// Buttonコンポーネントをインポート
import { Button } from "@/components/button";
import { Task } from "@/types/task";
type Props = {
tasks: Task[];
};
export function Table({ tasks }: Props) {
// ルーターを取得
const router = useRouter();
return (
<table className="w-full [&_td]:p-2 [&_td]:border">
<thead>
<tr>
<td>タイトル</td>
<td className="w-2/3">内容</td>
{/* ボタンのための列を追加 */}
<td className="w-20"></td>
</tr>
</thead>
<tbody>
{/* 渡されたtasksを回してテーブルを列を作成する */}
{tasks.map((task, index) => (
<tr key={index}>
<td>{task.title}</td>
<td>{task.content}</td>
<td>
<Button
onClick={() => {
// 詳細ページに遷移する処理
router.push(`/task/${index}`);
}}
>
詳細
</Button>
</td>
</tr>
))}
</tbody>
</table>
);
}
http://localhost:3000/taskから詳細ページにアクセスし、以下の画像のようになっていればOK
-
一覧ページ
-
詳細ページ
Discussion