Стратегии получения данных
Как выбрать получение REST-данных с учётом рендера страницы.
Перед выбором стратегии должен быть создан REST-клиент сервиса. Если клиента ещё нет, начните с раздела Создание клиента.
Сначала определите рендер страницы
В Next.js выбор начинается не с await, Suspense или SWR. Сначала нужно понять, какой рендер получится у маршрута: static/ISR или dynamic/SSR.
Next.js может перевести страницу в dynamic rendering автоматически, если в маршруте используются API текущего запроса. Поэтому первый вопрос такой:
Можно ли сохранить ISR, или странице нужны данные на каждый request?ISR — приоритет. Если данные общие для пользователей и их можно обновлять с интервалом, не переводите страницу в SSR без необходимости.
SSR/dynamic rendering выбирается только когда данные действительно зависят от текущего request или должны пересчитываться на каждый запрос.
Что переводит страницу в dynamic rendering
Проверьте, нужны ли странице API и настройки, которые делают маршрут динамическим:
cookies()— данные зависят от cookie текущего пользователя.headers()— данные зависят от request headers.draftMode()— нужен preview/draft-режим.searchParamsвpage.tsx— данные зависят от query string.cache: 'no-store'илиrevalidate: 0в методе клиента — запрос нельзя кешировать.connection()— рендер явно ждёт request.export const dynamic = 'force-dynamic'— SSR включён вручную.
Если ничего из этого не нужно, сначала проектируйте страницу как static/ISR. Серверный await сам по себе не означает SSR: режим зависит от кеширования запроса и dynamic API маршрута.
Рендер перед стратегией
| Рендер | Когда подходит | Что выбирать дальше |
|---|---|---|
| Static/ISR | Данные общие и могут обновляться по интервалу | Серверные стратегии: await, Promise.all, передача промиса ниже, SWR fallback |
| SSR/dynamic | Данные зависят от request, пользователя или должны быть свежими на каждый запрос | Серверные стратегии с учётом блокировки первого HTML |
| После гидрации | Данные зависят от вкладки, фильтра, поиска, пагинации или действия пользователя | Клиентский GET-хук |
Как выбрать стратегию
Когда режим рендера понятен, выбирайте конкретный способ получения данных:
| Ситуация после выбора рендера | Стратегия | Где читать |
|---|---|---|
Данные обязательны для первого HTML, SEO, notFound() или redirect() | Серверный await | Серверный await |
| Несколько независимых данных нужны до рендера | Запуск промисов + Promise.all | Параллельные серверные запросы |
| Часть UI можно загрузить отдельно | Передача промиса ниже + Suspense | Передача промиса ниже |
| Client Component должен получить данные сразу из SWR | Начальные данные для клиентских хуков | Начальные данные для клиентских хуков |
| Данные зависят от client state | Клиентский GET-хук | Клиентский GET-хук |
Нужно объединить несколько запросов или вычислить isAuth, canEdit, hasPets | Business-композиция | Business-композиция |
Правило выбора
Не выбирайте стратегию по любимому инструменту. Выбирайте её по двум вопросам:
Можно ли сохранить ISR?
Где нужны данные и что должно произойти до первого HTML?Если данные можно кешировать между пользователями — сохраняйте static/ISR. Если данные request-specific — используйте SSR/dynamic rendering. Если данные зависят от состояния браузера — используйте GET-хук REST-клиента. Если простой GET превращается в доменный сценарий — переходите в business/.
Общие запреты
// Плохо — SSR включён на всякий случай
export const dynamic = 'force-dynamic'
// Плохо — ISR отключён без требования к свежести на каждый request
export const revalidate = 0
// Плохо — прямой fetch в компоненте
useEffect(() => {
fetch('/api/pets').then(...)
}, [])
// Плохо — useSWR в компоненте
const { data } = useSWR(
['pet-store-api', 'pet', 'list', status],
() => petStoreApi.pet.findPetsByStatus({ status }),
)
// Плохо — бизнес-флаг внутри GET-хука REST-клиента
return {
...query,
hasPets: Boolean(query.data?.length),
}Не отключайте ISR без причины. В компонентах используются готовые методы клиента или готовые хуки. SWR-ключи, fetcher и транспорт остаются внутри REST-модуля.