- Добавлена документация SLM-архитектуры, базовых правил и прикладных разделов - Добавлены разделы: стили, SVG-спрайты, шаблоны генерации, PostCSS, REST, Realtime - Удалены устаревшие файлы (спрайты, скрипты, стили из app/)
89 lines
4.0 KiB
Markdown
89 lines
4.0 KiB
Markdown
---
|
||
title: Серверный await
|
||
description: Получение REST-данных на сервере до первого HTML.
|
||
keywords: [rest, server components, await, nextjs, isr, ssr, notFound, redirect]
|
||
---
|
||
|
||
# Серверный await
|
||
|
||
Получение REST-данных на сервере до первого HTML.
|
||
|
||
Серверный `await` — базовая стратегия для данных, которые нужны до рендера страницы или серверного блока.
|
||
|
||
## Когда использовать
|
||
|
||
- Данные нужны для первого HTML.
|
||
- Данные влияют на `metadata`.
|
||
- По результату запроса нужно вызвать `notFound()` или `redirect()`.
|
||
- Компонент серверный и данные не зависят от состояния браузера.
|
||
|
||
## Влияние на рендер
|
||
|
||
Серверный `await` сам по себе не означает SSR. В App Router страница может остаться static/ISR, если маршрут не использует dynamic API и запросы можно кешировать.
|
||
|
||
ISR — приоритет для общих данных. Если список или детальная страница могут обновляться по интервалу, сохраняйте кеширование и не добавляйте `no-store`, `revalidate: 0` или `force-dynamic` без требования.
|
||
|
||
SSR/dynamic rendering нужен, когда данные зависят от текущего request: cookie, headers, `searchParams`, preview-режим или персональные данные пользователя.
|
||
|
||
## Пример страницы списка
|
||
|
||
```tsx
|
||
// src/app/(routes)/pets/page.tsx
|
||
import { petStoreApi } from 'infrastructure/pet-store-api'
|
||
import { PetsScreen } from 'screens/pets'
|
||
|
||
export default async function PetsPage() {
|
||
const pets = await petStoreApi.pet.findPetsByStatus({
|
||
status: 'available',
|
||
})
|
||
|
||
return <PetsScreen pets={pets} />
|
||
}
|
||
```
|
||
|
||
`page.tsx` получает данные первого рендера и передаёт их ниже. UI страницы остаётся в `screens/`, а не пишется прямо в `app/`.
|
||
|
||
## Пример детальной страницы
|
||
|
||
```tsx
|
||
// src/app/(routes)/pets/[id]/page.tsx
|
||
import { notFound } from 'next/navigation'
|
||
import { petStoreApi } from 'infrastructure/pet-store-api'
|
||
import { PetDetailScreen } from 'screens/pet-detail'
|
||
|
||
type PetPageProps = {
|
||
params: Promise<{ id: string }>
|
||
}
|
||
|
||
export default async function PetPage({ params }: PetPageProps) {
|
||
const { id } = await params
|
||
const pet = await petStoreApi.pet.getPetById(Number(id)).catch(() => null)
|
||
|
||
if (!pet) {
|
||
notFound()
|
||
}
|
||
|
||
return <PetDetailScreen pet={pet} />
|
||
}
|
||
```
|
||
|
||
Обработка 404 зависит от API-клиента и класса ошибок. В примере показана идея: решение о `notFound()` принимается на уровне маршрута, а не внутри REST-клиента.
|
||
|
||
## Что не делать
|
||
|
||
```tsx
|
||
// Плохо — хуки нельзя вызывать в Server Component
|
||
const { data } = useGetPetList('available')
|
||
|
||
// Плохо — прямой fetch в обход клиента
|
||
const response = await fetch('https://petstore3.swagger.io/api/v3/pet/findByStatus')
|
||
```
|
||
|
||
Если данные нужны на сервере, вызывайте метод REST-клиента напрямую.
|
||
|
||
## Когда выбрать другую стратегию
|
||
|
||
- Несколько независимых запросов — [Параллельные серверные запросы](./parallel-server-requests.md).
|
||
- Часть UI можно грузить отдельно — [Передача промиса ниже](./pass-promise-down.md).
|
||
- Данные нужны клиентскому хуку сразу после гидрации — [Начальные данные для клиентских хуков](./client-hooks-initial-data.md).
|