Next.js / Page ба Layout

Page ба Layout

Өмнөх хичээлд page.tsx файл үүсгэж хуудас нэмэхийг сурлаа. Одоо layout гэдэг ойлголтыг судална. Layout бол хуудсуудын нийтлэг бүрхүүл — navbar, footer зэргийг нэг удаа бичиж бүх хуудасд автоматаар харуулах боломжийг олгодог.

layout.tsx гэж юу вэ?

layout.tsx бол хүүхэд хуудсуудаа children prop-оор хүлээн авч бүрхэн харуулдаг component. Аль ч route-д layout.tsx нэмж болно:

код
app/
├── layout.tsx        ← Бүх хуудасд нийтлэг (root layout)
├── page.tsx          ← / хуудас
└── courses/
    ├── layout.tsx    ← /courses/* хуудасд нийтлэг
    └── page.tsx      ← /courses хуудас

Root layout

app/layout.tsx бол заавал байх ёстой файл — бүх хуудасны гадаад бүрхүүл. HTML бүтцийг энд тодорхойлдог:

tsx
// app/layout.tsx
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";

const geistSans = Geist({ subsets: ["latin"], variable: "--font-geist-sans" });
const geistMono = Geist_Mono({
  subsets: ["latin"],
  variable: "--font-geist-mono",
});

export const metadata: Metadata = {
  title: "ulaanbaatar.app",
  description: "Монголын кодчиллын платформ",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="mn">
      <body className={`${geistSans.variable} ${geistMono.variable}`}>
        <nav>Navbar энд</nav>
        {children}
        <footer>Footer энд</footer>
      </body>
    </html>
  );
}

children гэдэг нь тухайн URL-д тохирох page.tsx-н гаралт. /about хаягаар ороход children = AboutPage-н гаралт болно.

Nested layout — давхар layout

courses/ директорт өөрийн layout.tsx нэмж болно. Энэ layout нь root layout-н дотор render хийгдэнэ:

tsx
// app/courses/layout.tsx
export default function CoursesLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex">
      <aside>
        {/* Курсуудын sidebar */}
        <p>Sidebar энд</p>
      </aside>
      <main className="flex-1">{children}</main>
    </div>
  );
}

Одоо /courses болон /courses/javascript хаягаар ороход аль аль нь энэ sidebar-тай харагдана. /about хаягаар ороход sidebar харагдахгүй — зөвхөн root layout ажиллана.

Давхарлалт ийм харагдана:

код
RootLayout
└── CoursesLayout
    └── page.tsx (CoursePage эсвэл LessonPage)

page.tsx ба layout.tsx-н ялгаа

| | page.tsx | layout.tsx | | --------------- | -------------------------- | --------------------------- | | Зориулалт | Хуудасны агуулга | Бүрхүүл, навигаци | | children prop | Байхгүй | Заавал байна | | Дахин render | URL солигдоход | Дахин render хийгдэхгүй | | Заавал эсэх | Тийм (хуудас болохын тулд) | Үгүй |

Layout дахин render хийгдэхгүй гэдэг нь маш чухал — хэрэглэгч /courses/courses/javascript руу шилжихэд layout хэвээр үлдэж, зөвхөн children солигдоно. Энэ нь гүйцэтгэлийг сайжруулдаг.

metadata экспорт

Хуудас бүр metadata объект экспортолж SEO мэдээллийг тохируулж болно:

tsx
// app/courses/page.tsx
import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "Сургалтууд | ulaanbaatar.app",
  description: "JavaScript, React, Next.js болон бусад курсууд",
};

export default function CoursesPage() {
  return <h1>Сургалтууд</h1>;
}

Dynamic хуудасд generateMetadata функц ашиглана:

tsx
// app/courses/[courseSlug]/page.tsx
import type { Metadata } from "next";

interface Props {
  params: Promise<{ courseSlug: string }>;
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { courseSlug } = await params;
  return {
    title: `${courseSlug} | ulaanbaatar.app`,
  };
}

export default async function CoursePage({ params }: Props) {
  const { courseSlug } = await params;
  return <h1>{courseSlug}</h1>;
}

Дараагийн хичээлд:

Хуудсуудын хооронд шилжихэд <Link> component ашиглана. Энгийн <a> тэгийн оронд <Link> ашиглах нь яагаад чухал болохыг ойлгоно.