← Назад к курсу

Пособие по Next.js (App Router)

1. Введение

Next.js — это React-фреймворк для создания полноценных веб-приложений. Он решает такие задачи, как:

  • Маршрутизация на основе файловой системы
  • Различные стратегии рендеринга: SSR (серверный), SSG (статический), ISR (инкрементальный), CSR (клиентский)
  • Оптимизация изображений, шрифтов, скриптов
  • API‑маршруты и Server Actions
  • Отличный опыт разработки с поддержкой TypeScript, быстрой перезагрузкой (Fast Refresh)

Пособие ориентировано на App Router (Next.js 13+), который является современным стандартом.

2. Установка и создание проекта

Требования: Node.js 18.17 или выше.

npx create-next-app@latest my-app

В процессе установки ответьте на вопросы (TypeScript, ESLint, Tailwind CSS, src/ directory, App Router, импорт алиасы).

Перейдите в проект и запустите:

cd my-app
npm run dev

Откройте http://localhost:3000.

3. Структура проекта (App Router)

Ключевая папка — app/. Внутри неё располагаются маршруты, макеты, страницы.

my-app/
├── app/
│   ├── layout.tsx        # Корневой макет (обязателен)
│   ├── page.tsx          # Домашняя страница (/)
│   ├── about/
│   │   └── page.tsx      # /about
│   └── blog/
│       ├── page.tsx      # /blog
│       └── [slug]/
│           └── page.tsx  # /blog/:slug (динамический)
├── public/               # статика
├── components/           # переиспользуемые компоненты (по желанию)
└── ...

Основные файлы:

  • page.tsx — экспортирует React‑компонент, который становится страницей.
  • layout.tsx — обёртка для страниц и вложенных маршрутов.
  • loading.tsx — fallback при Suspense.
  • error.tsx — компонент ошибки (Error Boundary).
  • not-found.tsx — страница 404 для конкретного сегмента.

4. Маршрутизация

4.1 Статические маршруты

Создаём папку и внутри неё page.tsx:

// app/about/page.tsx
export default function AboutPage() {
  return <h1>О нас</h1>;
}

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

Используйте квадратные скобки [param].

// app/blog/[slug]/page.tsx
interface Props {
  params: { slug: string };
}

export default function BlogPost({ params }: Props) {
  return <h1>Пост: {params.slug}</h1>;
}

4.3 Группы маршрутов (для логической группировки без влияния на URL)

Папка в круглых скобках (group) не попадает в URL.

app/
  (marketing)/
    about/page.tsx   -> /about
    contact/page.tsx -> /contact
  (shop)/
    products/page.tsx -> /products

4.4 Вложенные макеты

Каждая папка может содержать свой layout.tsx, который обернёт все страницы внутри неё.

// app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div>
      <aside>Меню панели</aside>
      <main>{children}</main>
    </div>
  );
}

4.5 Шаблоны (template.tsx)

Аналогичен layout, но при навигации внутри группы не сохраняет состояние (пересоздаётся). Полезен, когда нужно сбрасывать состояние.

5. Рендеринг и компоненты

5.1 Серверные компоненты (по умолчанию)

Все компоненты в app/ по умолчанию серверные. Они выполняются на сервере, HTML отправляется клиенту. Преимущества:

  • Доступ к серверным ресурсам (БД, файловая система)
  • Меньше JavaScript на клиенте
  • Безопасность (приватные данные не утекают)
// app/products/page.tsx
import { db } from '@/lib/db';

export default async function ProductsPage() {
  const products = await db.product.findMany(); // прямая работа с БД
  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

5.2 Клиентские компоненты (use client)

Добавьте директиву 'use client' в начало файла. Используется для интерактивности: хуки, обработчики событий, эффекты, браузерные API.

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Счёт: {count}</button>;
}

Важно: Директива работает только на границе файла. Компоненты, импортированные в клиентский, тоже становятся клиентскими.

6. Получение данных

6.1 Асинхронные компоненты

Серверные компоненты могут быть async, данные получаются прямо в рендере.

// app/users/page.tsx
async function getUsers() {
  const res = await fetch('https://jsonplaceholder.typicode.com/users', {
    cache: 'force-cache', // SSG – см. раздел о кэшировании
  });
  return res.json();
}

export default async function UsersPage() {
  const users = await getUsers();
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

6.2 Кэширование fetch

По умолчанию fetch в серверных компонентах использует кэш по умолчанию (аналог force-cache). Поведение:

  • cache: 'force-cache' – данные запрашиваются один раз при сборке (SSG) или при первом запросе (постоянный кэш)
  • cache: 'no-store' – всегда свежие данные (SSR)
  • next: { revalidate: 60 } – ISR (перегенерация каждые 60 секунд)

6.3 Клиентское получение данных (SWR, React Query)

В клиентских компонентах используйте useEffect или библиотеки:

'use client';
import useSWR from 'swr';

function Profile() {
  const { data } = useSWR('/api/user', fetcher);
  return <div>{data?.name}</div>;
}

7. Стратегии рендеринга

Стратегия Описание Когда использовать
SSG (Static Site Generation) HTML генерируется во время сборки. Очень быстро, подходит для блогов, документации. Данные не меняются часто.
SSR (Server‑Side Rendering) HTML генерируется на сервере при каждом запросе. Персонализированный контент, свежие данные.
ISR (Incremental Static Regeneration) Статическая генерация с возможностью фонового обновления. Компромисс между скоростью и актуальностью.
CSR (Client‑Side Rendering) Рендеринг на клиенте после загрузки JS. Интерактивные панели, приватные зоны.

Как задать стратегию в App Router

  • SSG – fetch с { cache: 'force-cache' } (по умолчанию) и статические динамические параметры через generateStaticParams.
  • SSR – fetch с { cache: 'no-store' } или использование динамических функций (cookies(), headers()).
  • ISR – fetch с { next: { revalidate: 60 } }.
  • CSR – клиентский компонент с хуками (useEffect, SWR).

Пример динамических параметров для SSG:

// app/posts/[id]/page.tsx
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then(res => res.json());
  return posts.map((post) => ({ id: String(post.id) }));
}

8. API маршруты (Route Handlers)

Создайте файл route.ts внутри папки app/api/.... Поддерживаются методы GET, POST, PUT, PATCH, DELETE.

// app/api/hello/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ message: 'Hello, World!' });
}

export async function POST(request: Request) {
  const body = await request.json();
  // логика...
  return NextResponse.json({ received: body }, { status: 201 });
}

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

// app/api/users/[id]/route.ts
export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.user.findUnique({ where: { id: params.id } });
  return NextResponse.json(user);
}

9. Server Actions

Позволяют вызывать серверный код из клиентских компонентов без создания API. Доступны в Next.js 14+.

// app/actions.ts
'use server';

export async function createPost(formData: FormData) {
  const title = formData.get('title');
  await db.post.create({ data: { title } });
}

Использование в клиентском компоненте:

'use client';
import { createPost } from './actions';

export function NewPostForm() {
  return (
    <form action={createPost}>
      <input name="title" />
      <button type="submit">Создать</button>
    </form>
  );
}

10. Оптимизация

10.1 Изображения (next/image)

Автоматически оптимизирует размер, формат (WebP/AVIF), lazy‑загрузку.

import Image from 'next/image';

export default function Logo() {
  return (
    <Image
      src="/logo.png"
      width={200}
      height={100}
      alt="Логотип"
      priority // для LCP
    />
  );
}

10.2 Шрифты (next/font)

Загружайте шрифты без утечки макета (CLS).

import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

export default function RootLayout({ children }) {
  return (
    <html lang="ru" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

10.3 Скрипты (next/script)

Для сторонних скриптов:

import Script from 'next/script';

<Script
  src="https://example.com/script.js"
  strategy="lazyOnload" // после загрузки страницы
/>

11. Стилизация

  • CSS Modules – по умолчанию (файлы *.module.css)
  • Tailwind CSS – рекомендован, отлично интегрируется
  • CSS‑in‑JS (styled‑components, Emotion) – требует настройки, но работает на клиенте
// компонент с CSS Modules
import styles from './Button.module.css';

export default function Button() {
  return <button className={styles.primary}>Click</button>;
}

12. Middleware

Middleware выполняется перед обработкой запроса. Позволяет перенаправлять, изменять заголовки, проверять аутентификацию.

// middleware.ts в корне проекта
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname === '/admin') {
    const token = request.cookies.get('token');
    if (!token) {
      return NextResponse.redirect(new URL('/login', request.url));
    }
  }
  return NextResponse.next();
}

export const config = {
  matcher: ['/admin/:path*'],
};

13. Деплой

Самый простой способ – Vercel

npm run build
# Связать проект с Vercel через CLI или Git-интеграцию

Альтернативы: Node.js сервер, Docker, статический экспорт

  • Статический экспорт (только SSG): output: 'export' в next.config.js
  • Node.js сервер: next start (после сборки)
  • Docker: официальные образы от Vercel.

14. Полезные советы

  • Используйте TypeScript – Next.js отлично с ним работает.
  • Для отладки серверных компонентов включите logging в консоли терминала.
  • next/dynamic для lazy‑загрузки клиентских компонентов.
  • useRouter из next/navigation для навигации в клиентских компонентах.
  • Следите за размером бандла с помощью @next/bundle-analyzer.

15. Заключение

Next.js с App Router даёт мощные инструменты для создания производительных приложений. Освоив маршрутизацию, серверные компоненты, стратегии рендеринга и оптимизации, вы сможете строить проекты любого масштаба – от лендинга до сложного SaaS.

Дальнейшее изучение:

Удачи в разработке!

Дополнительный материал

Вопросы учеников к ИИ-помощнику и ответы по теме урока

Вопрос: Анонимный пользователь · 2026-04-30 16:42
в чем разница между некстом и вордпрессом?
Ответ ИИ:

Отличный вопрос! Это сравнение двух принципиально разных инструментов, хотя оба используются для создания сайтов.

Основная мысль: Next.js — это фреймворк для разработчиков, который позволяет создавать высокопроизводительные, кастомные веб-приложения на React. WordPress — это готовая система управления контентом (CMS), которая позволяет создавать сайты без глубоких знаний программирования, используя готовые темы и плагины.

Ключевые различия:

  • Назначение и сложность:
    • Next.js: Для создания сложных, уникальных веб-приложений (интернет-магазины, соцсети, дашборды). Требует знания JavaScript/React.
    • WordPress: Для сайтов с упором на контент (блоги, новостные порталы, простые корпоративные сайты). Подходит для новичков.
  • Управление контентом:
    • Next.js: Контент хранится в коде, базе данных или подключается из внешних CMS (как "головная" часть). Редактировать контент без разработчика сложно.
    • WordPress: Имеет встроенный визуальный редактор. Контент может редактировать любой пользователь.
  • Производительность и гибкость:
    • Next.js: Дает полный контроль над кодом и рендерингом (SSR, SSG). Очень высокая скорость и масштабируемость.
    • WordPress: Производительность сильно зависит от хостинга, темы и количества плагинов. Может быть медленным без оптимизации.
  • Безопасность:
    • Next.js: Более безопасен, так как не имеет популярной "панели администратора", которую взламывают.
    • WordPress: Частая цель для атак из-за популярности и уязвимостей в плагинах.

Короткое упражнение для закрепления:
Подумайте, какой инструмент вы бы выбрали для:
1. Сайта-визитки для небольшой кофейни (нужно просто показать меню и контакты, обновлять раз в месяц).
2. Стартапа, создающего новый сервис для онлайн-бронирования столиков (нужна уникальная логика, авторизация, работа с API).

Ответ: 1 — WordPress (быстро и просто), 2 — Next.js (нужна гибкость и производительность).