Пособие по 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.
Дальнейшее изучение:
- Официальная документация: nextjs.org/docs
- Next.js Learn: learn.nextjs.org
- Примеры из репозитория vercel/next.js/examples
Удачи в разработке!
Дополнительный материал
Вопросы учеников к ИИ-помощнику и ответы по теме урока
Отличный вопрос! Это сравнение двух принципиально разных инструментов, хотя оба используются для создания сайтов.
Основная мысль: 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 (нужна гибкость и производительность).