SSR в Next.js: React на полной мощности
Содержание
- Введение: проблема SPA и рождение SSR
- Что такое Next.js и почему он популярен
- Создание проекта Next.js
- Маршрутизация в Next.js (pages router)
- Навигация между страницами (Link)
- SSR vs SSG vs ISR (три способа рендеринга)
- Получение данных в Next.js
- API Routes (создание API внутри Next.js)
- Оптимизация изображений (next/image)
- Продвинутые возможности Next.js
- React Router vs Next.js (сравнение)
- Частые ошибки новичков
- Итог (что мы узнали)
- Задание для закрепления (на 2–3 часа)
- Что дальше?
Цель урока: понять, что такое Server Side Rendering (SSR), зачем он нужен и как Next.js упрощает создание React-приложений с рендерингом на сервере. Научиться создавать многостраничные приложения с улучшенным SEO, быстрой загрузкой и богатым функционалом «из коробки».
Введение: проблема SPA и рождение SSR
React-приложения по умолчанию — это Single Page Applications (SPA). Весь JavaScript загружается в браузер один раз, а затем React управляет страницей.
Проблемы SPA
- SEO (поисковая оптимизация) — поисковые боты не всегда выполняют JavaScript, поэтому они видят пустую страницу с
<div id="root"></div> - Первая загрузка — пользователь видит пустой экран, пока загружается весь JavaScript
- Производительность — на слабых устройствах загрузка может быть медленной
Главная мысль: SSR (Server Side Rendering) решает эти проблемы, рендеря React-компоненты на сервере и отправляя готовый HTML в браузер. Пользователь видит страницу сразу, а React «оживает» её после загрузки JavaScript.
Два подхода
| Подход | Что происходит | Когда использовать |
|---|---|---|
| SPA (Create React App, Vite) | Рендеринг в браузере | Админки, внутренние приложения |
| SSR (Next.js) | Рендеринг на сервере | Публичные сайты, интернет-магазины |
Что такое Next.js и почему он популярен
(откроется в новой вкладке)Next.js — это фреймворк на основе React, созданный компанией Vercel.
Что даёт Next.js «из коробки»:
- SSR и SSG — рендеринг на сервере и генерация статики
- Автоматическая маршрутизация — страницы создаются из папки pages/
- API Routes — создание API-эндпоинтов внутри приложения
- Оптимизация изображений — автоматическое сжатие и lazy loading
- Hot Module Replacement — мгновенное обновление при разработке
- Zero Config — почти нет настроек
Главная мысль: Next.js — это «React на максималках». Ты получаешь все возможности React плюс SSR, SEO, производительность и множество удобных инструментов.
Сравнение с другими
| Create React App | Vite | Next.js | |
|---|---|---|---|
| SSR | ❌ Нет | ❌ Нет | ✅ Есть |
| SEO | ❌ Плохое | ❌ Плохое | ✅ Отличное |
| Настройка | Простая | Простая | Простая |
| Маршрутизация | Вручную (React Router) | Вручную | Автоматическая |
| Размер бандла | Большой | Маленький | Оптимизированный |
Создание проекта Next.js
Установка:
npx create-next-app@latest my-next-app
cd my-next-app
npm run dev
Структура проекта:
my-next-app/
├── pages/ # Страницы (маршрутизация)
│ ├── _app.jsx # Глобальная обёртка
│ ├── index.jsx # Главная страница ( / )
│ └── about.jsx # Страница /about
├── public/ # Статические файлы
├── styles/ # Стили (CSS Modules)
├── package.json
└── next.config.js # Конфигурация
Первый компонент (pages/index.jsx):
export default function Home() {
return (
<div>
<h1>Привет, Next.js!</h1>
<p>Это SSR-приложение на React</p>
</div>
);
}
Важно: ты просто создаёшь файл в pages/ — и он автоматически становится страницей по пути, соответствующему имени файла!
Маршрутизация в Next.js (pages router)
Файловая маршрутизация — просто и удобно:
| Файл | URL | Что рендерится |
|---|---|---|
pages/index.jsx |
/ |
Главная страница |
pages/about.jsx |
/about |
Страница «О нас» |
pages/blog.jsx |
/blog |
Блог |
pages/blog/post.jsx |
/blog/post |
Конкретный пост |
pages/users/[id].jsx |
/users/123 |
Динамический параметр |
Динамические маршруты:
// pages/users/[id].jsx
import { useRouter } from 'next/router';
export default function UserProfile() {
const router = useRouter();
const { id } = router.query;
return <h1>Профиль пользователя {id}</h1>;
}
// /users/123 → id = "123"
Оживи свой сайт. Освой JavaScript!
Статичная верстка — это только скелет. Наш онлайн-курс "JavaScript с нуля до профи" даст твоим страницам мышцы и нервы. Научись создавать слайдеры, формы, интерактивные карты и получать данные с сервера.
От теории — к реальным скриптам в твоём портфолио.
Навигация между страницами (Link)
import Link from 'next/link';
export default function Navigation() {
return (
<nav>
<Link href="/">Главная</Link>
<Link href="/about">О нас</Link>
<Link href="/blog">Блог</Link>
<Link href="/users/123">Пользователь 123</Link>
</nav>
);
}
Важно: next/link работает как React Router, но с предзагрузкой страниц для мгновенного перехода.
SSR vs SSG vs ISR (три способа рендеринга)
| Способ | Что происходит | Когда использовать |
|---|---|---|
| SSR (Server Side Rendering) | Рендерится на сервере при каждом запросе | Динамические данные, персонализация |
| SSG (Static Site Generation) | Рендерится один раз при сборке | Блоги, статические сайты |
| ISR (Incremental Static Regeneration) | Обновляется периодически после сборки | Каталоги товаров, новостные сайты |
SSG (генерируется при сборке):
// pages/blog.jsx
export async function getStaticProps() {
// Загружаем данные при сборке
const response = await fetch('https://api.example.com/posts');
const posts = await response.json();
return {
props: { posts }, // Передаём в компонент
};
}
export default function Blog({ posts }) {
return (
<div>
<h1>Блог</h1>
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
SSR (рендерится при каждом запросе):
// pages/dashboard.jsx
export async function getServerSideProps() {
// Загружаем данные при каждом запросе
const response = await fetch('https://api.example.com/dashboard');
const data = await response.json();
return {
props: { data },
};
}
export default function Dashboard({ data }) {
return <div>Панель управления: {data}</div>;
}
ISR (обновляется периодически):
export async function getStaticProps() {
const response = await fetch('https://api.example.com/products');
const products = await response.json();
return {
props: { products },
revalidate: 60, // Пересоздавать страницу каждые 60 секунд
};
}
Получение данных в Next.js
На клиенте (useEffect, как в обычном React):
import { useState, useEffect } from 'react';
export default function ClientSideData() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(res => res.json())
.then(setData);
}, []);
return <div>{data}</div>;
}
На сервере (getStaticProps / getServerSideProps):
// Страница с данными, полученными на сервере
export async function getStaticProps() {
const response = await fetch('https://api.example.com/posts');
const posts = await response.json();
return {
props: { posts },
};
}
export default function Blog({ posts }) {
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
API Routes (создание API внутри Next.js)
Next.js позволяет создавать API-эндпоинты прямо в приложении:
// pages/api/users.js
export default function handler(req, res) {
if (req.method === 'GET') {
res.status(200).json([
{ id: 1, name: 'Алексей' },
{ id: 2, name: 'Мария' }
]);
} else {
res.status(405).json({ error: 'Метод не разрешён' });
}
}
// Теперь доступно по адресу: /api/users
Оптимизация изображений (next/image)
import Image from 'next/image';
export default function Home() {
return (
<Image
src="/images/photo.jpg"
alt="Описание"
width={800}
height={600}
quality={80}
priority // Для ключевых изображений (LCP)
/>
);
}
Что даёт:
- Автоматическое сжатие и оптимизация
Lazy loading(по умолчанию)- WebP-формат для поддерживаемых браузеров
Resizeна лету
Продвинутые возможности Next.js
Глобальные стили (_app.jsx):
// pages/_app.jsx
import '../styles/globals.css';
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
SEO через next/head:
import Head from 'next/head';
export default function Home() {
return (
<>
<Head>
<title>Мой сайт | Главная</title>
<meta name="description" content="Описание страницы" />
<meta property="og:title" content="Мой сайт" />
</Head>
<div>Контент</div>
</>
);
}
Middleware (для логирования, авторизации):
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(request) {
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
React Router vs Next.js (сравнение)
| Характеристика | React Router | Next.js |
|---|---|---|
| SSR/SSG | ❌ Нет | ✅ Есть |
| SEO | ❌ Плохое | ✅ Отличное |
| Маршрутизация | Ручная (через код) | Автоматическая (по папкам) |
| Настройка | Требуется дополнительная | Zero Config |
| Размер бандла | Оптимизируется вручную | Автоматическая оптимизация |
| API Routes | Нет | Есть |
| Когда использовать | SPA, админки, внутренние приложения | Публичные сайты, магазины |
Частые ошибки новичков
| Ошибка | Почему | Исправление |
|---|---|---|
| Используют клиентские API на сервере | window, localStorage не существуют на сервере |
Используй useEffect или проверку typeof window !== 'undefined' |
Не используют Link для навигации |
Полная перезагрузка страницы | Используй next/link |
Забывают про _app.jsx |
Глобальные стили не применяются | Добавь импорт стилей в _app.jsx |
| Не оптимизируют изображения | Медленная загрузка | Используй next/image |
Используют getServerSideProps для статики |
Лишняя нагрузка на сервер | Используй getStaticProps |
Итог (что мы узнали)
| Что узнали | Как это работает |
|---|---|
| SSR | Рендеринг на сервере для SEO и скорости |
| Next.js | Фреймворк для React с SSR «из коробки» |
| Файловая маршрутизация | Страницы автоматически по папкам |
getStaticProps |
Генерация статики при сборке |
getServerSideProps |
Рендеринг при каждом запросе |
Link |
Навигация без перезагрузки |
| API Routes | Создание API внутри приложения |
| ISR | Обновление статики периодически |
Задание для закрепления (на 2–3 часа)
Создай Next.js-приложение с тремя страницами:
- Главная страница (
/) — используйgetStaticPropsдля загрузки списка постов с публичного API (например,JSONPlaceholder) - Страница поста (
/posts/[id]) — используйgetStaticPathsиgetStaticPropsдля генерации страниц всех постов - Страница «О нас» (
/about) — статическая страница с SEO-оптимизацией (Headсtitleиdescription)
Дополнительно:
- Добавь навигацию между страницами через
next/link - Используй
next/imageдля аватаров пользователей - Добавь API-роут
/api/users, который возвращает список пользователей
Проверка: убедись, что все страницы работают, навигация происходит мгновенно, а при отключённом JavaScript контент всё равно виден (проверь через инспектор «Disable JavaScript»).
Скачать код выполненного задания на GitHub: (откроется в новой вкладке)SSR в Nextjs
Что дальше?
В следующем уроке разберём React Query — мощную библиотеку для работы с серверными данными. Ты узнаешь, как управлять кешированием, перезапросом, пагинацией и оптимистичными обновлениями. Это сделает работу с API простой и эффективной.