Как в SSR составляется состояние для рендера?
Что проверяют
Понимаете ли вы весь путь данных: сервер получил данные, отрендерил HTML, передал то же состояние клиенту, и клиент гидратировался без расхождений. Следом часто спрашивают про Next.js App Router и про то, почему серверный стор не делают синглтоном.
Как отвечать
Классическая схема из четырёх шагов:
- сбор данных: на каждый запрос сервер загружает всё, что нужно странице, часто параллельно через
Promise.all; - стор на запрос: для Redux и подобных создаётся новый стор под каждый запрос и заполняется через
preloadedState; - рендер:
renderToPipeableStreamили фреймворк рендерит дерево с этим состоянием в HTML; - передача: состояние сериализуется в HTML, например в
<script type="application/json">илиwindow.__INITIAL_STATE__, клиент создаёт стор из него и вызываетhydrateRoot.
В Next.js Pages Router эту роль играет getServerSideProps: его результат уходит в props страницы и в __NEXT_DATA__. В App Router отдельного объекта состояния нет: серверные компоненты сами получают данные через async, а клиентским компонентам достаются только сериализуемые props внутри RSC payload. Для TanStack Query данные предзагружают на сервере в QueryClient, передают через dehydrate и HydrationBoundary, и на клиенте запрос не повторяется.
Что стоит добавить: передавать нужно минимум, потому что данные едут дважды, в разметке и в JSON. Через JSON не проходят функции и классы, а Date превращается в строку. Всё, что зависит от браузера (window, localStorage, часовой пояс), нельзя читать во время рендера, иначе серверный и клиентский HTML разойдутся.
Где спотыкаются
Делают стор синглтоном на уровне модуля. На сервере модуль живёт между запросами, и данные одного пользователя попадают в страницу другого.
Вставляют JSON.stringify(state) прямо в <script> без экранирования. Строка </script> в пользовательских данных закрывает тег, и это готовая XSS. Символ < нужно экранировать, например в \u003c.
Не могут объяснить ошибку гидратации. Причина обычно в Date.now(), Math.random(), проверке typeof window в рендере или в разном форматировании дат на сервере и клиенте.