Стратегии рендеринга и получение данных
Разбираемся, когда строится HTML страницы и как опции fetch выбирают стратегию рендеринга.
В Next.js один и тот же React-код можно отдавать тремя способами: SSG (HTML при сборке), SSR (на каждый запрос) и ISR (пересборка по таймеру); а сам выбор делается опциями
fetch.
Три стратегии
| Стратегия | Когда строится HTML | Подходит для |
| SSG (Static) | Один раз при build | Блог, документация, лендинги |
| SSR (Dynamic) | На каждый запрос | Лента, персональная страница, корзина |
| ISR (Incremental) | При сборке + пересборка по таймеру | Каталог товаров, новости |
SSG — самый быстрый вариант: статика создаётся один раз и раздаётся (можно через CDN). SSR нужен, когда контент персональный или обязан быть всегда свежим. ISR — компромисс: страница статическая, но «протухает» через интервал и тихо пересобирается в фоне.
Данные грузят обычным fetch
В App Router не нужны useEffect и состояние загрузки. Серверный компонент — async, и вы просто ждёте данные:
// app/products/page.tsx — серверный компонент
export default async function ProductsPage() {
const res = await fetch("https://api.example.com/products");
const products = await res.json();
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
Запрос уходит с сервера, в браузер едет уже готовый HTML со списком.
Опции кэша = стратегия
Ключевая идея: в App Router стратегию рендеринга выбирают не отдельными функциями, а опциями fetch:
| Опции fetch | Поведение | Эффект |
{ cache: "force-cache" } | Кэшировать | SSG (статика) |
{ next: { revalidate: 60 } } | Обновлять не чаще раза в 60 с | ISR |
{ cache: "no-store" } | Грузить каждый раз | SSR (динамика) |
// всегда свежие данные → страница станет динамической (SSR)
const res = await fetch(url, { cache: "no-store" });
// ревалидация раз в минуту → ISR
const res2 = await fetch(url, { next: { revalidate: 60 } });
Дедупликация запросов
Если несколько компонентов делают одинаковый fetch с одним URL, Next.js за один рендер выполнит запрос один раз и переиспользует результат — данные можно грузить там, где они нужны, не пробрасывая пропсами. Смоделируем идею на чистом JS:
const cache = new Map();
function cachedFetch(url) {
if (cache.has(url)) {
console.log("из кэша:", url);
return cache.get(url);
}
console.log("запрос:", url);
const data = { url, ok: true };
cache.set(url, data);
return data;
}
cachedFetch("/api/user");
cachedFetch("/api/user");
cachedFetch("/api/posts");
Вывод:
запрос: /api/user из кэша: /api/user запрос: /api/posts
Итог
- SSG — HTML на сборке (быстро); SSR — на каждый запрос; ISR — статика с фоновой пересборкой.
- Данные грузят обычным
fetchвasync-серверном компоненте, безuseEffect. - Опции
cache/revalidateуfetchи задают стратегию; одинаковые запросы дедуплицируются.