1. Архитектура App Router: Server Components и работа со специальными хуками (useServerInsertedHTML, usePathname)
Архитектура App Router: Server Components и работа со специальными хуками (useServerInsertedHTML, usePathname)
Next.js v16 продолжает развивать парадигму, заложенную в App Router, где основой архитектуры являются React Server Components (RSC). Понимание того, как серверные и клиентские компоненты взаимодействуют, а также умение управлять потоком данных и стилей через специальные хуки — критически важный навык для создания производительных приложений.
React Server Components (RSC) как стандарт
В директории app все компоненты по умолчанию являются Server Components. Это фундаментальный сдвиг по сравнению с классическим React или Pages Router в Next.js.
Преимущества серверного рендеринга по умолчанию
moment или date-fns) внутри серверного компонента, она останется на сервере. Клиент получит только готовый HTML.Пример типичного серверного компонента:
Клиентские компоненты и директива 'use client'
Серверные компоненты не поддерживают интерактивность (onClick, onChange) и хуки React (useState, useEffect). Для этого используются Client Components.
Чтобы превратить компонент в клиентский, необходимо добавить директиву 'use client' в самой первой строке файла. Это создает границу между серверным и клиентским кодом.
Паттерн композиции: "Дырки" в клиентских компонентах
Распространенная ошибка — импортировать серверный компонент внутрь клиентского. Это приведет к тому, что серверный компонент станет клиентским (попадет в бандл). Чтобы сохранить преимущества RSC, используйте паттерн children.
Неправильно:
Правильно:
В правильном варианте ServerComponent рендерится на сервере, а его результат передается в ClientWrapper как проп children. Клиентский компонент отвечает только за расположение этого контента, но не за его генерацию.
Хук usePathname: Навигация и активные состояния
В App Router глобальный объект router из next/router больше не используется. Вместо этого навигация разделена на несколько хуков, доступных только в клиентских компонентах ('use client').
Хук usePathname возвращает текущий путь URL. Это основной инструмент для создания активных ссылок в меню или условного рендеринга элементов интерфейса в зависимости от страницы.
Важно помнить, что usePathname вызывает повторный рендеринг клиентского компонента при смене маршрута. Поэтому старайтесь использовать его в небольших изолированных компонентах (например, только в навигационной панели), а не в корневом Layout, чтобы избежать лишних перерисовок всего приложения.
Хук useServerInsertedHTML: CSS-in-JS и потоковый рендеринг
Одной из самых сложных задач при переходе на App Router стала интеграция библиотек CSS-in-JS (таких как styled-components, emotion или mantine). Проблема заключается в том, что RSC использует потоковую передачу (streaming) HTML. Браузер начинает получать и отображать контент еще до того, как весь React-код будет выполнен.
Если стили генерируются на лету (runtime), может возникнуть эффект FOUC (Flash of Unstyled Content) — пользователь увидит "голый" HTML, который затем резко изменится после загрузки JS.
Хук useServerInsertedHTML из next/navigation решает эту проблему. Он позволяет внедрять теги <style> в поток HTML в момент генерации серверных компонентов, до того как они попадут к клиенту.
Этот хук работает только внутри клиентских компонентов, которые используются в качестве оберток (Registry) в корневом layout.tsx.
Пример реализации CSS Registry
Рассмотрим упрощенную схему интеграции библиотеки стилей:
Как это работает:
useServerInsertedHTML, он выполняет колбэк.Это гарантирует, что даже при медленном интернете пользователь сразу увидит стилизованный контент, так как CSS приходит вместе с HTML.
Оптимизация и границы сериализации
При передаче данных (props) от серверного компонента к клиентскому, данные должны быть сериализуемыми. Это означает, что они должны быть представимы в формате JSON.
Что можно передавать:
* Строки, числа, булевы значения.
* Массивы и простые объекты.
* null, undefined.
Что нельзя передавать напрямую:
* Функции (например, обработчики событий).
* Экземпляры классов (кроме Date, который автоматически преобразуется в строку).
* Сложные объекты с циклическими ссылками.
Если вам нужно передать функцию (например, Server Action) в клиентский компонент, она должна быть импортирована из файла с директивой 'use server' или определена внутри серверного компонента как async-функция.
Итоги
'use client': Используйте эту директиву только для компонентов, требующих интерактивности (state, effects, browser API).usePathname заменяет router.pathname и работает только в клиентских компонентах для отслеживания URL.useServerInsertedHTML критически важен для корректной работы CSS-in-JS библиотек в среде потокового рендеринга, предотвращая мигание стилей.children, чтобы избежать их ненужной конвертации в клиентский код.