Dynamic маршрут
Бодит апп дахь хуудас бүр статик биш — /courses/javascript, /courses/react, /courses/python гэх мэт олон хуудас нэг загвараас үүсдэг. Next.js-д үүнийг dynamic route ашиглан хялбархан шийддэг. Энэ хичээлд dynamic маршрутыг дэлгэрэнгүй судална.
[slug] параметр
Директорын нэрийг хаалтанд бичихэд тухайн сегмент dynamic болно:
app/courses/[courseSlug]/page.tsx
Энэ нэг файл дараах бүх хаягт зориулан ажиллана:
/courses/javascript → courseSlug = "javascript"
/courses/react → courseSlug = "react"
/courses/python → courseSlug = "python"
/courses/go → courseSlug = "go"
params prop-оор параметрийн утгыг авна. Next.js 15-д params бол Promise тул заавал await хийнэ:
// app/courses/[courseSlug]/page.tsx
interface Props {
params: Promise<{ courseSlug: string }>;
}
export default async function CoursePage({ params }: Props) {
const { courseSlug } = await params;
return (
<main>
<h1>{courseSlug} курс</h1>
</main>
);
}
Бодит жишээ — курсын хуудас
Файл системээс курсын мэдээллийг уншиж харуулах жишээ:
// app/courses/[courseSlug]/page.tsx
import { notFound } from "next/navigation";
import { getCourse } from "@/lib/courses";
import type { Metadata } from "next";
interface Props {
params: Promise<{ courseSlug: string }>;
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { courseSlug } = await params;
const course = await getCourse(courseSlug);
if (!course) return { title: "Олдсонгүй" };
return {
title: `${course.title} | ulaanbaatar.app`,
description: course.description,
};
}
export default async function CoursePage({ params }: Props) {
const { courseSlug } = await params;
const course = await getCourse(courseSlug);
if (!course) {
notFound(); // 404 хуудас руу шилжүүлнэ
}
return (
<main className="p-6">
<h1 className="text-3xl font-bold text-white">{course.title}</h1>
<p className="mt-2 text-slate-400">{course.description}</p>
<ul className="mt-6 space-y-2">
{course.lessons.map((lesson) => (
<li key={lesson.slug}>
<a
href={`/courses/${courseSlug}/${lesson.slug}`}
className="text-indigo-400 hover:underline"
>
{lesson.order}. {lesson.title}
</a>
</li>
))}
</ul>
</main>
);
}
Nested dynamic параметр
Курс болон хичээл хоёуланг dynamic байлгахад nested параметр ашиглана:
app/courses/[courseSlug]/[lessonSlug]/page.tsx
// app/courses/[courseSlug]/[lessonSlug]/page.tsx
import { notFound } from "next/navigation";
import { getCourse, getLesson } from "@/lib/courses";
interface Props {
params: Promise<{
courseSlug: string;
lessonSlug: string;
}>;
}
export default async function LessonPage({ params }: Props) {
const { courseSlug, lessonSlug } = await params;
const course = await getCourse(courseSlug);
const lesson = await getLesson(courseSlug, lessonSlug);
if (!course || !lesson) {
notFound();
}
return (
<article className="prose prose-invert max-w-3xl mx-auto p-6">
<p className="text-slate-400 text-sm">
{course.title} / {lesson.title}
</p>
<h1 className="text-white">{lesson.title}</h1>
{/* Хичээлийн агуулга энд */}
</article>
);
}
generateStaticParams — урьдчилан үүсгэх
Production build хийхэд Next.js dynamic хуудсуудыг урьдчилан статик HTML болгон үүсгэж болно — энэ нь хуудсыг маш хурдан болгодог. generateStaticParams функц нь бүх боломжит параметрүүдийн жагсаалтыг буцаана:
// app/courses/[courseSlug]/page.tsx-д нэмнэ
import { getAllCourses } from "@/lib/courses";
export async function generateStaticParams() {
const courses = await getAllCourses();
return courses.map((course) => ({
courseSlug: course.slug,
}));
}
// Next.js build хийхэд /courses/javascript, /courses/react г.м.
// хуудас бүрийг автоматаар HTML болгон үүсгэнэ
Nested dynamic параметртэй хуудасд ийм байна:
// app/courses/[courseSlug]/[lessonSlug]/page.tsx-д нэмнэ
export async function generateStaticParams() {
const courses = await getAllCourses();
const params = [];
for (const course of courses) {
for (const lesson of course.lessons) {
params.push({
courseSlug: course.slug,
lessonSlug: lesson.slug,
});
}
}
return params;
}
notFound() ашиглах
Dynamic хуудасд байхгүй slug ирвэл notFound() функцийг дуудна. Энэ нь app/not-found.tsx хуудсыг харуулна:
// app/not-found.tsx
import Link from "next/link";
export default function NotFoundPage() {
return (
<main className="flex flex-col items-center justify-center min-h-screen">
<h1 className="text-4xl font-bold text-white">404</h1>
<p className="mt-2 text-slate-400">Хуудас олдсонгүй</p>
<Link href="/" className="mt-4 text-indigo-400 hover:underline">
Нүүр хуудас руу буцах
</Link>
</main>
);
}
Дараагийн хичээлд:
Catch-all болон optional маршрутыг судална. [...slug] ба [[...slug]] синтакс ашиглан нэг хуудсаар олон түвшний замыг барих аргыг ойлгоно.