Урок 02

App Router и страницы

App Router — современный роутинг Next.js. Файлы в app/ автоматически становятся маршрутами.

Базовые файлы

  • page.tsx — страница (публичный маршрут)
  • layout.tsx — общий layout
  • loading.tsx — состояние загрузки
  • error.tsx — обработка ошибок
  • not-found.tsx — 404
  • route.ts — API-роут

Простая страница

app/page.tsx:

export default function Home() {
    return <h1>Главная</h1>;
}

app/about/page.tsx:

export default function About() {
    return <h1>О нас</h1>;
}

URL: /about.

Вложенные папки

app/
├── page.tsx              → /
├── about/
│   └── page.tsx          → /about
├── blog/
│   ├── page.tsx          → /blog
│   └── post/
│       └── page.tsx      → /blog/post

Папка = сегмент URL. page.tsx делает сегмент доступным.

Динамические маршруты

app/posts/[id]/page.tsx:

export default async function Post({ params }: { params: Promise<{ id: string }> }) {
    const { id } = await params;
    return <h1>Пост {id}</h1>;
}

URL: /posts/1, /posts/2, /posts/hello.

Catch-all

app/docs/[...slug]/page.tsx:

export default async function Docs({ params }: { params: Promise<{ slug: string[] }> }) {
    const { slug } = await params;
    return <p>Путь: {slug.join('/')}</p>;
}

Ловит /docs/a, /docs/a/b, /docs/a/b/c.

Опциональный catch-all

[[...slug]] — ловит и /docs без сегментов:

app/docs/[[...slug]]/page.tsx

Группы маршрутов

Папки в скобках не попадают в URL:

app/
├── (marketing)/
│   ├── about/page.tsx     → /about
│   └── contact/page.tsx   → /contact
└── (shop)/
    ├── cart/page.tsx      → /cart
    └── checkout/page.tsx  → /checkout

Используются для группировки по layout или логике.

Link

import Link from 'next/link';

<Link href="/about">О нас</Link>
<Link href={`/posts/${post.id}`}>{post.title}</Link>

Link делает клиентскую навигацию и предзагрузку.

useRouter

Программная навигация:

'use client';

import { useRouter } from 'next/navigation';

export default function Button() {
    const router = useRouter();

    return <button onClick={() => router.push('/about')}>О нас</button>;
}

Методы: push, replace, back, forward, refresh, prefetch.

usePathname и useSearchParams

'use client';

import { usePathname, useSearchParams } from 'next/navigation';

const pathname = usePathname();
const searchParams = useSearchParams();
const page = searchParams.get('page');

Метаданные

export const metadata = {
    title: 'О нас',
    description: 'Описание страницы',
};

Динамические:

export async function generateMetadata({ params }) {
    const { id } = await params;
    const post = await getPost(id);
    return { title: post.title };
}

Итоги

  • Файлы в app/ — маршруты
  • page.tsx — страница
  • [id] — динамический сегмент
  • [...slug] — catch-all
  • (group) — группа без URL
  • Link для навигации
  • metadata для SEO