
กำลังโหลด...

กำลังโหลด...

เชื่อมลิงก์ได้แล้ว! ตอนนี้พี่อยากให้หน้ารายละเอียดดึงข้อมูลของโพสต์นั้นจริงๆ มาแสดง (title, body) ไม่ใช่แค่โชว์เลข id เฉยๆ
เป้าหมายของ Mission นี้: ทำให้หน้ารายละเอียดดึงข้อมูลของโพสต์นั้นมาแสดงจริง
flowchart TD
A["เปิดหน้า /posts/[id]"] --> B["fetch โพสต์ตาม params.id"]
B --> C{"สำเร็จไหม?"}
C -->|"กำลังโหลด"| D["โชว์ กำลังโหลด..."]
C -->|"error"| E["โชว์ ไม่พบโพสต์นี้"]
C -->|"สำเร็จ"| F["โชว์รายละเอียดโพสต์"]
Mission ก่อนหน้าเขียนหน้า Detail เป็น Server Component (async + await params) แต่ Mission นี้
ต้องใช้ useState / useEffect เพื่อทำ Loading กับ Error State — พอใส่ "use client" แล้วจะ
await params ไม่ได้ (Client Component เป็น async ไม่ได้) ให้แกะค่าออกมาด้วย use() ของ React แทน
// app/posts/[id]/page.tsx
"use client";
import { use, useState, useEffect } from "react";
type Post = { id: number; title: string; body: string };
export default function PostDetailPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = use(params); // Client Component แกะ params ด้วย use() แทน await
const [post, setPost] = useState<Post | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
async function loadPost() {
setLoading(true); // สลับไปโพสต์อื่นต้องกลับไปสถานะกำลังโหลดใหม่
setError("");
try {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${id}`,
);
if (!response.ok) throw new Error("ไม่พบโพสต์นี้");
const data = await response.json();
setPost(data);
} catch (err) {
setError("โหลดข้อมูลไม่สำเร็จ");
} finally {
setLoading(false);
}
}
loadPost();
}, [id]); // ดึงข้อมูลใหม่ทุกครั้งที่ id เปลี่ยน (เช่นสลับไปดูโพสต์อื่น)
if (loading) return <p>กำลังโหลด...</p>;
if (error) return <p className="text-red-600">{error}</p>;
if (!post) return <p>ไม่พบโพสต์</p>;
return (
<article className="p-8">
<h1 className="text-2xl font-bold">{post.title}</h1>
<p className="mt-4 text-neutral-600">{post.body}</p>
</article>
);
}
สังเกต:
[id]ในuseEffectdependency array บอก React ว่า "ถ้า id เปลี่ยน ให้รันโค้ดข้างในใหม่" — สำคัญมาก เพราะถ้าลืมใส่ พอสลับไปดูโพสต์อื่นข้อมูลจะไม่อัปเดตให้
ระวัง: ถ้าเขียนเป็น
params.idตรงๆ ในไฟล์ที่มี"use client"จะไม่ได้ค่าที่ต้องการ เพราะparamsเป็น Promise ต้องแกะด้วยuse(params)ก่อนเสมอ (ตัวอย่างเก่าๆ ในอินเทอร์เน็ต ที่เขียนparams.idได้เลย คือ Next.js เวอร์ชันก่อนหน้า)
ทดสอบคลิกลิงก์จากหน้า /posts ไปหลายๆ โพสต์ดู — Chapter นี้จบแล้ว เหลือแค่ Mini Project ปิด
ท้ายคอร์ส!