Когда в Next.js 13 появились Server Components, я отнёсся к ним скептически — ещё одна абстракция, которая усложнит жизнь. Но после нескольких месяцев работы с App Router понял: RSC (React Server Components) — это не просто модный термин, а реальный инструмент для решения конкретных проблем.
Server vs Client: где граница
Главный ментальный сдвиг: теперь у нас два типа компонентов с чёткими ограничениями:
// Server Component (по умолчанию)
async function UserProfile({ userId }) {
const user = await db.users.findUnique({ where: { id: userId } });
return <ProfileCard user={user} />;
}
// Client Component (явная пометка)
'use client';
function LikeButton() {
const [likes, setLikes] = useState(0);
return <button onClick={() => setLikes(l + 1)}>Likes: {likes}</button>;
}
На практике я выработал простое правило: если компонент не использует useState, useEffect или браузерные API (localStorage, window) — он должен быть Server Component. Особенно это касается:
- Data fetching слоя
- Статичных секций страниц
- Компоновки layout’ов
Data fetching без боли
Раньше типичный сценарий выглядел так:
- Рендерим скелетон
- Летит запрос на API роут
- Получаем данные
- Обновляем UI
С RSC схема упрощается до:
// Раньше
function Page() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/posts').then(r => r.json()).then(setData);
}, []);
return data ? <Posts posts={data} /> : <Loader />;
}
// Теперь
async function Page() {
const posts = await db.posts.findMany();
return <Posts posts={posts} />;
}
Но есть нюанс: нельзя просто взять и заменить все useEffect на прямые запросы к БД. Важно учитывать:
- Топ-уровневые страницы (layout, page) — идеальные кандидаты на RSC
- Глубоко вложенные компоненты могут создать waterfall запросов
- Для мутаций всё равно нужны Client Components + API роуты
Постепенная миграция
Главный страх при внедрении RSC — необходимость переписывать весь проект. На практике я рекомендую такой подход:
- Новые страницы — сразу делаем на App Router
- Критические пути (например, главная) — оставляем в Pages Router, пока не протестируем RSC
- Изолированные фичи — переводим по одной, начиная с самых “тяжёлых”
Пример гибридного роутинга в Next.js:
/app
/dashboard # Новый RSC-роут
/pages
/index.tsx # Старая страница
Подводные камни
После полугода работы с RSC я собрал список неочевидных проблем:
-
Интеграция с внешними библиотеками
Многие UI-киты пока не адаптированы под Server Components. Например, попытка использоватьuseClientвнутри библиотечного компонента может сломать сборку. -
Отладка
Ошибки в Server Components иногда дают малопонятные stack traces. Приходится включатьNEXT_VERBOSE=1и копать логи сервера. -
Кеширование
По умолчанию Next.js агрессивно кеширует RSC. Это хорошо для перфоманса, но может сбивать с толку при разработке. Решение — явно настраиватьfetchOptions.cache.
RSC — не серебряная пуля. Для SPA-подобных приложений с богатой клиентской логикой они могут добавить сложности без явных выгод. Но для content-heavy сайтов (блоги, маркетплейсы, медиа) — это реальный способ сократить TTI (Time To Interactive) на 20-40%.
Что попробовать дальше:
- Поиграться с streaming для прогрессивной загрузки
- Протестировать комбинацию RSC + React Suspense
- Перенести на RSC один сложный data-fetching сценарий в существующем проекте