Dynamic Pages from Data
Next.js App Router ใช้ generateStaticParams() เพื่อระบุ dynamic routes ตอน build time Next Pages Router ใช้ getStaticPaths() Astro ก็ใช้ getStaticPaths() ในไฟล์ [slug].astro — ชื่อเดียวกับ Pages Router แต่คุณ return array ของ object ที่มี key params (จะมี key props ด้วยก็ได้) แล้วเข้าถึงผ่าน Astro.props และ Astro.params ใน frontmatter
ต้องใช้โปรเจกต์ Astro เต็มรูปแบบถึงจะรันได้ ใช้
npm create astro@latestเพื่อสร้างโปรเจกต์
App Router generateStaticParams vs Astro getStaticPaths
หัวข้อที่มีชื่อว่า “App Router generateStaticParams vs Astro getStaticPaths”// app/blog/[slug]/page.tsx (Next.js App Router)import { allPosts } from 'contentlayer/generated';
export async function generateStaticParams() { return allPosts.map(post => ({ slug: post.slug }));}
export default function PostPage({ params }) { const post = allPosts.find(p => p.slug === params.slug); return ( <article> <h1>{post.title}</h1> <p>{post.description}</p> </article> );}---// src/pages/blog/[slug].astro (Astro)import { getCollection, render } from 'astro:content';
export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map(post => ({ params: { slug: post.id }, props: { post }, }));}
const { post } = Astro.props;const { Content } = await render(post);---<article> <h1>{post.data.title}</h1> <Content /></article>ใน Astro, getStaticPaths กับ page template อยู่ในไฟล์เดียวกัน key props ให้คุณส่ง collection entry ทั้งก้อนไปตรง ๆ ได้เลย — ไม่ต้อง lookup ซ้ำอีกรอบ
Pages Router getStaticPaths vs Astro
หัวข้อที่มีชื่อว่า “Pages Router getStaticPaths vs Astro”// pages/blog/[slug].tsx (Next.js Pages Router)export async function getStaticPaths() { const posts = await fetchAllPosts(); // or contentlayer return { paths: posts.map(p => ({ params: { slug: p.slug } })), fallback: false, };}
export async function getStaticProps({ params }) { const post = await fetchPost(params.slug); return { props: { post } };}
export default function PostPage({ post }) { return ( <article> <h1>{post.title}</h1> <div dangerouslySetInnerHTML={{ __html: post.contentHtml }} /> </article> );}---// src/pages/blog/[slug].astro (Astro)import { getCollection, render } from 'astro:content';
export async function getStaticPaths() { const posts = await getCollection('blog'); // params defines the URL; props pass data to the page return posts.map(post => ({ params: { slug: post.id }, props: { post }, }));}
// Both params and props land here — no second getStaticProps neededconst { post } = Astro.props;const { Content } = await render(post);---<article> <h1>{post.data.title}</h1> <Content /></article>Next Pages Router แยก path enumeration (getStaticPaths) ออกจาก data fetching (getStaticProps) Astro รวมสองอย่างเข้าด้วยกัน: ส่ง props ไปพร้อมกับ getStaticPaths แล้วข้าม round-trip รอบที่สองไปได้เลย
Complete dynamic route page
หัวข้อที่มีชื่อว่า “Complete dynamic route page”---import { getCollection, render } from 'astro:content';import BaseLayout from '../../layouts/BaseLayout.astro';
export async function getStaticPaths() { const posts = await getCollection('blog', ({ data }) => !data.draft); return posts.map((post) => ({ params: { slug: post.id }, props: { post }, }));}
const { post } = Astro.props;const { Content, headings } = await render(post);const { title, date, tags = [] } = post.data;---<BaseLayout title={title}> <article> <header> <h1>{title}</h1> <time datetime={date.toISOString()}> {date.toLocaleDateString('en-US', { dateStyle: 'long' })} </time> {tags.length > 0 && ( <ul class="tags"> {tags.map((tag) => <li>{tag}</li>)} </ul> )} </header> <Content /> </article></BaseLayout>