Вы уже пишете приложения на React. Умеете создавать компоненты, работать с useState, подключать API и настраивать маршруты. Для небольшого проекта этого достаточно. Но со временем появляются новые задачи. Нужно показывать страницы товаров по отдельным адресам, получать данные на сервере, управлять метаданными и публиковать сайт без сложной ручной настройки.
Возникает вопрос, продолжать развивать React-приложение с выбранными библиотеками или перейти на Next.js. Разберём различия на примере каталога товаров и определим, когда переход имеет смысл.
Next.js не заменяет React
React, библиотека для построения пользовательского интерфейса. Она отвечает за компоненты, состояние, обработку действий и отображение данных.
Next.js, фреймворк, построенный на React. В нём вы продолжаете писать React-компоненты, но получаете готовую систему маршрутов, серверного рендеринга, загрузки данных и сборки приложения.
Поэтому сравнение не совсем похоже на выбор двух независимых технологий. Вопрос скорее в том, нужна ли вашему React-проекту структура и серверные возможности, которые предоставляет Next.js. Если вы делаете небольшое браузерное приложение, где пользователь открывает одну страницу и работает с локальными данными, React вместе с Vite может полностью решать задачу. Переход на Next.js только ради другого названия технологии не требуется.
Когда обычного клиентского приложения достаточно
Представим внутреннюю панель управления. Пользователь входит в систему, открывает таблицы и редактирует записи. Почти все данные поступают из защищённого API, а поисковые системы не должны индексировать страницы кабинета. Такое приложение можно построить на React с клиентской маршрутизацией. Для работы с формами, запросами и состоянием при необходимости добавляются библиотеки. Сама по себе их установка не означает, что архитектура неправильная.
Другой пример интерактивный инструмент, который выполняет расчёты в браузере и не нуждается в серверной загрузке страниц. Здесь Next.js может добавить новые понятия без заметной пользы для задачи. Переход оправдан, когда появляются требования, которые удобнее решать средствами фреймворка, а не отдельными настройками.
Что меняется в маршрутизации
В обычном React-приложении маршруты часто описывают через отдельную библиотеку. В Next.js App Router адреса определяются структурой папок. Например, файл app/catalog/page.tsx соответствует странице /catalog, а app/catalog/[id]/page.tsx странице конкретного товара с динамическим параметром.
Можно создавать общие макеты через layout.tsx, вложенные маршруты и отдельные состояния загрузки. Это помогает организовать приложение, в котором много взаимосвязанных страниц. Но готовая маршрутизация не отменяет проектирование. Названия URL, вложенность разделов и поведение переходов всё равно придётся продумать.
Как выглядит первая страница в Next.js
Для небольшого примера создадим страницу каталога в App Router.
// app/catalog/page.tsx
const products = [
{ id: 1, name: "Кофе" },
{ id: 2, name: "Чай" },
];
export default function CatalogPage() {
return (
<main>
<h1>Каталог</h1>
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</main>
);
}
Здесь обычный React-компонент становится страницей по адресу /catalog благодаря расположению файла. Для такого статического примера не требуется useState или клиентский JavaScript для вычисления списка.
В Next.js App Router страницы и макеты по умолчанию являются серверными компонентами. Это позволяет получать данные и подготавливать интерфейс на сервере. Но не все компоненты нужно делать серверными. Интерактивные части продолжают работать в браузере.
Где остаются useState и обработчики событий
Предположим, у каждой карточки товара появилась кнопка «В избранное». Она меняет состояние после нажатия. Для такой задачи нужен клиентский компонент с директивой "use client".
"use client";
import { useState } from "react";
export default function FavoriteButton() {
const [saved, setSaved] = useState(false);
return (
<button
type="button"
aria-pressed={saved}
onClick={() => setSaved((value) => !value)}
>
{saved ? "В избранном" : "В избранное"}
</button>
);
}
Такой компонент можно использовать внутри серверной страницы каталога. Он отвечает за нажатие и изменение интерфейса, а страница за получение и отображение данных. Это один из подходов Next.js. Не обязательно переводить весь сайт в клиентский режим ради одной интерактивной кнопки. При этом локальное состояние из примера исчезнет после полной перезагрузки. Для постоянного избранного потребуется отдельное хранилище.
Механика состояния разобрана в статье «Как работает useState в React на примере избранных товаров».
Что даёт серверная загрузка данных
В клиентском React-приложении данные часто загружаются после открытия страницы в браузере. Интерфейс сначала показывает оболочку или индикатор загрузки, затем получает ответ API.
В Next.js серверный компонент может выполнить запрос до передачи готового интерфейса браузеру. Это подходит для каталога, статьи или страницы товара, где содержимое связано с адресом. Но Next.js не делает любой запрос автоматически быстрее. Результат зависит от источника данных, времени ответа сервера, настроек кэширования и способа рендеринга. Серверные запросы также требуют обработки ошибок. Для приложений с публичными страницами это даёт больше возможностей управлять тем, какой HTML получает посетитель и поисковый робот.
А что насчёт SEO
В React-приложении тоже можно создавать индексируемые страницы. Однако для каталога с большим числом маршрутов часто приходится отдельно решать задачи формирования HTML, метаданных и индексации.
Next.js предоставляет инструменты для генерации метаданных, sitemap и серверного рендеринга. Это удобно, когда товары, статьи и другие публичные страницы должны иметь собственные адреса и содержимое. При этом использование Next.js само по себе не гарантирует позиции в поиске. Нужно отдельно выбирать, какие страницы индексировать, как связывать их между собой и какие данные показывать.
Для внутренних панелей, закрытых личных кабинетов и инструментов без публичных страниц SEO обычно не является причиной менять фреймворк.
Нужно ли переписывать существующий проект
Не обязательно переносить всё приложение сразу. Начните с небольшой самостоятельной страницы и проверьте, как в Next.js организованы маршруты, данные и интерактивные компоненты. Знакомые React-компоненты часто можно использовать повторно. Но код, который обращается к window, localStorage или событиям браузера, требует внимания к границе между сервером и клиентом.
Также предстоит пересмотреть маршрутизацию, переменные окружения и способы загрузки данных. Если проект уже стабильно работает на React с Vite, стоимость перехода нужно сравнить с ожидаемыми преимуществами. Официальная инструкция Next.js по миграции с React-приложения описывает подход к переносу существующего проекта с Vite.
От React-компонентов к приложению на Next.js
В моей статье на Habr о Route Handlers показано, как внутри Next.js появляется серверная часть для работы с запросами. Это один из вариантов развития приложения, которому уже недостаточно только клиентского интерфейса.
В Goods Finder можно посмотреть каталог на Next.js с маршрутизацией, поиском и пользовательскими действиями.
Курс «Next.js I: JavaScript 2026» рассчитан на переход от знакомых принципов JavaScript и React к App Router, загрузке данных, URL-фильтрам и деплою приложения.
Выбирайте Next.js не потому, что React перестал справляться с компонентами. Переход имеет смысл, когда проекту нужны встроенные маршруты, серверная работа с данными и управление публичными страницами. Для небольшого клиентского приложения React с привычными инструментами может оставаться достаточным решением.