Cache Components у Next.js 16: use cache, PPR та питання для співбесід у 2026 році

Повний посібник з Cache Components у Next.js 16: директива use cache, Partial Pre-Rendering, cacheLife, cacheTag, Instant Navigations у 16.3 та питання для senior-розробників на співбесідах.

Cache Components у Next.js 16 - use cache, PPR та питання для співбесід

Cache Components у Next.js 16 являють собою найбільшу зміну в підході до кешування з часу впровадження App Router. Попередня модель кешувала все за замовчуванням і вимагала явної відмови. Нова модель не кешує нічого за замовчуванням і вимагає явного увімкнення за допомогою директиви "use cache". У версії Next.js 16.3, випущеній у серпні 2026, Cache Components отримали функцію Instant Navigations: набір інструментів, що забезпечує швидкість відгуку на рівні SPA для серверних застосунків.

Фундаментальна зміна ментальної моделі

Next.js 16 переходить від неявного кешування (все кешується, відмова через динамічні API) до явного кешування (нічого не кешується, увімкнення через "use cache"). Next.js 16.3 розширює цю модель Partial Prefetching та Instant Navigations, завдяки чому явна модель працює так само швидко, як односторінковий застосунок.

Чому Next.js 16 замінив неявне кешування

Модель неявного кешування в Next.js 14-15 створювала проблеми з передбачуваністю. Виклик fetch всередині Server Component автоматично дедуплікувався та кешувався, але чи була сторінка статичною чи динамічною залежало від використаних API. Налагодження поведінки кешу вимагало розуміння кількох прихованих шарів: кешу fetch, кешу повного маршруту та кешу маршрутизатора.

Next.js 16 видаляє всі три неявні кеші. Кожна сторінка рендериться динамічно при кожному запиті, якщо явно не позначена директивою "use cache". Експорт revalidate видалено. unstable_cache замінено усвідомленою компілятором директивою "use cache". Повний обсяг цих змін описано в офіційному блозі Next.js 16.

Ця зміна обмінює автоматичну оптимізацію на явний контроль. Продуктивність може спочатку знизитися в застосунках, що покладалися на неявне кешування, але досвід налагодження суттєво покращується: кешований контент кешується тому, що код так каже, а не через евристики фреймворку.

Як працює директива use cache на трьох рівнях

Директива "use cache" працює на трьох рівнях: файлу, компонента та функції. Вибір правильного рівня це найважливіше рішення щодо кешування в Next.js 16.

Кешування на рівні файлу позначає кожен асинхронний експорт у файлі як кешований. Підходить для сторінок з виключно статичним контентом без даних, специфічних для користувача.

app/pricing/page.tsxtypescript
"use cache"

import { getPricingPlans } from "@/lib/data"

// Entire page is cached as a static shell
export default async function PricingPage() {
  const plans = await getPricingPlans()
  return (
    <section>
      {plans.map((plan) => (
        <PricingCard key={plan.id} plan={plan} />
      ))}
    </section>
  )
}

Кешування на рівні компонента кешує окремі компоненти на сторінці. Це уможливлює Partial Pre-Rendering: кешований компонент рендериться як частина статичної оболонки, тоді як динамічні сусіди передаються потоком під час запиту.

components/ProductRecommendations.tsxtsx
async function ProductRecommendations({ categoryId }: { categoryId: string }) {
  "use cache"
  // categoryId becomes part of the automatic cache key
  const products = await getTopProducts(categoryId)
  return (
    <ul>
      {products.map((p) => (
        <li key={p.id}>{p.name} - {p.price}</li>
      ))}
    </ul>
  )
}

Кешування на рівні функції спрямоване безпосередньо на функції отримання даних. Замінює старий патерн unstable_cache.

lib/data.tstypescript
import { cacheLife } from "next/cache"

export async function getArticleBySlug(slug: string) {
  "use cache"
  cacheLife("hours")
  // slug is automatically included in the cache key
  const article = await db.article.findUnique({ where: { slug } })
  return article
}

Компілятор автоматично генерує ключі кешування з аргументів функції. Жодних ручних масивів keyParts, жодних обхідних рішень з JSON.stringify. Аргументи повинні бути серіалізованими (рядки, числа, прості обʼєкти). Передача екземпляра класу або функції як аргументу порушує серіалізацію.

Instant Navigations у Next.js 16.3

Next.js 16.3 вирішує найпоширенішу критику Server Components: навігації відчуваються повільними, оскільки вимагають мережевої затримки. Instant Navigations виправляють це шляхом попереднього завантаження багаторазових оболонок на маршрут, а не на посилання.

Увімкніть Instant Navigations двома прапорцями в next.config.ts:

next.config.tstypescript
import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
}

export default nextConfig

З partialPrefetching: true Next.js витягує оболонку завантаження з кожного маршруту та кешує її на стороні клієнта. Коли користувач натискає на посилання, оболонка рендериться миттєво, поки динамічний контент передається потоком. Це той самий патерн швидкості відгуку, який використовують односторінкові застосунки, але без відмови від серверного рендерингу.

Stream, Cache або Block

Для кожної асинхронної операції на маршруті потрібно обрати: Stream з <Suspense> (миттєвий стан завантаження), Cache з "use cache" (миттєвий кешований UI) або Block з export const instant = false (очікування сервера). Перші два забезпечують миттєві навігації.

Navigation Inspector у Next.js DevTools дозволяє призупинити навігації на рівні оболонки, щоб побачити, що саме попередньо завантажується. Instant Insights автоматично виявляють повільні навігації під час розробки та перетворюють їх на помилки для вирішення.

Partial Pre-Rendering з Partial Prefetching

Partial Pre-Rendering (PPR) був експериментальним у Next.js 14-15. У Next.js 16 PPR є стабільним і інтегрованим безпосередньо з Cache Components через cacheComponents: true. Next.js 16.3 розширює це Partial Prefetching, який змінює спосіб доставки оболонок клієнту.

До 16.3 Next.js надсилав запит prefetch для кожного посилання у видимій області. З Partial Prefetching попередньо завантажується одна оболонка на маршрут. Двадцять посилань на /chat/[id] викликають один prefetch, а не двадцять. Це зменшує мережеве навантаження та робить стратегію prefetch схожою на те, як SPA розділяють код на маршрути.

app/dashboard/page.tsxtsx
import { Suspense } from "react"
import { UserGreeting } from "@/components/UserGreeting"
import { StaticSidebar } from "@/components/StaticSidebar"
import { RecentActivity } from "@/components/RecentActivity"

export default function DashboardPage() {
  return (
    <div className="grid grid-cols-12 gap-6">
      {/* Cached static shell - prefetched and served instantly */}
      <StaticSidebar />

      <main className="col-span-9">
        {/* Dynamic - streams in after shell renders */}
        <Suspense fallback={<GreetingSkeleton />}>
          <UserGreeting />
        </Suspense>

        {/* Dynamic - streams independently */}
        <Suspense fallback={<ActivitySkeleton />}>
          <RecentActivity />
        </Suspense>
      </main>
    </div>
  )
}

Дерево рішень рендерингу: компоненти з "use cache" стають частиною статичної оболонки. Компоненти, загорнуті в <Suspense>, що читають cookies, headers або інші дані, специфічні для запиту, передаються потоком динамічно. Для prefetching на посилання поза оболонкою додайте <Link prefetch={true}> до конкретних посилань.

Профілі cacheLife: заміна revalidate

Експорт revalidate з Next.js 15 видалено. Натомість cacheLife() пропонує іменовані профілі для контролю тривалості кешу. Вбудовані профілі: seconds, minutes, hours, days, weeks та max.

lib/data.tstypescript
import { cacheLife } from "next/cache"

export async function getExchangeRates() {
  "use cache"
  cacheLife("minutes") // Revalidates every few minutes
  const rates = await fetch("https://api.exchangerate.host/latest")
  return rates.json()
}

export async function getCompanyInfo() {
  "use cache"
  cacheLife("weeks") // Rarely changes
  return db.company.findFirst()
}

Користувацькі профілі визначаються в next.config.ts:

next.config.tstypescript
import type { NextConfig } from "next"

const config: NextConfig = {
  cacheComponents: true,
  cacheLife: {
    // Custom profile for product data
    product: {
      stale: 300,      // Serve stale for 5 minutes
      revalidate: 3600, // Revalidate in background every hour
      expire: 86400,    // Hard expire after 24 hours
    },
  },
}

export default config

Централізація профілів у конфігурації означає, що одна зміна коригує кешування по всьому застосунку. Це усуває розкидані значення revalidate: 3600, які були проблемою кодових баз Next.js 15.

Одне правило, яке слід запамʼятати: cacheLife() повинен виконуватися лише один раз за виклик функції. Умовне кешування є допустимим лише тоді, коли виконується одна гілка.

Готовий до співбесід з React / Next.js?

Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.

cacheTag та updateTag для цільової інвалідації

Без cacheTag() кешована функція може закінчити термін дії лише за часом. Інвалідація за запитом вимагає тегування записів кешу та виклику revalidateTag() або нового updateTag() у Server Action.

lib/data.tstypescript
import { cacheLife, cacheTag } from "next/cache"

export async function getProductById(id: string) {
  "use cache"
  cacheTag(`product-${id}`, "products")
  cacheLife("days")
  return db.product.findUnique({ where: { id } })
}
app/actions.tstypescript
"use server"

import { updateTag } from "next/cache"

export async function updateProduct(id: string, data: ProductUpdate) {
  await db.product.update({ where: { id }, data })
  // Invalidate this specific product AND the product list
  updateTag(`product-${id}`)
  updateTag("products")
}

Різниця між revalidateTag та updateTag: обидва інвалідують, але updateTag є рекомендованим примітивом у Next.js 16.3, розробленим для безшовної роботи з новою моделлю кешування. Теги підтримують до 256 символів кожен, з максимумом 128 тегів на запис кешу.

Пастка відсутніх тегів

Кешована функція без cacheTag() може закінчити термін дії лише за часом. Інвалідація за запитом неможлива. Це легко пропустити під час початкової розробки та болісно виявити, коли клієнт повідомляє про застарілі дані на продакшені.

Безпека: варіанти use cache

За замовчуванням директива "use cache" створює спільний кеш. Будь-яка комбінація аргументів створює запис кешу, який може бути поданий будь-якому користувачу. Це правильно для публічних даних, але небезпечно для персоналізованого контенту.

"use cache: private" створює кеш на кожного користувача, який включає поточну сесію в ключ кешу. Може безпечно звертатися до cookies() та headers() в кешованому обсязі.

"use cache: remote" зберігає кеш у зовнішньому сховищі. У безсерверних середовищах (Vercel, AWS Lambda) кеш у памʼяті за замовчуванням втрачається при холодному старті. Remote caching забезпечує збереження записів кешу між екземплярами функцій, хоча вимагає мережевої затримки та зазвичай передбачає плату платформи.

typescript
// WRONG: User data in shared cache - data leak risk
export async function getUserDashboard(userId: string) {
  "use cache"
  return db.user.findUnique({
    where: { id: userId },
    include: { orders: true, preferences: true },
  })
}

// CORRECT: Private cache scoped to the current user
export async function getUserDashboard() {
  "use cache: private"
  cacheLife("minutes")
  const session = await cookies()
  const userId = session.get("userId")?.value
  return db.user.findUnique({
    where: { id: userId },
    include: { orders: true, preferences: true },
  })
}

Матриця рішень для співбесід:

ДирективаОбсягКоли використовувати
"use cache"Спільний, усі користувачіПублічні дані: прайси, статті, каталоги продуктів
"use cache: private"Сесія на користувачаПерсоналізовані дані: дашборди, налаштування, історія замовлень
"use cache: remote"Спільний, зовнішнє сховищеДані з високим трафіком у безсерверних середовищах

Root Params у Next.js 16.3

Next.js 16.3 представляє root params, вирішуючи надмірну передачу props для динамічних сегментів, визначених над кореневим layout. Root params, такі як [lang], є ефективно глобальними і потрібні по всьому дереву компонентів.

app/[lang]/posts/[slug]/page.tsxtsx
import { lang } from "next/root-params"

export default async function PostPage(
  props: PageProps<"/[lang]/posts/[slug]">
) {
  const { slug } = await props.params
  const language = await lang()

  return (
    <article>
      <p>Language: {language}</p>
      <p>Post: {slug}</p>
    </article>
  )
}

Root params працюють в обсягах use cache, і лише параметри, які дійсно читаються, стають частиною ключа кешу. Це робить патерни інтернаціоналізації більш ергономічними без порушення поведінки кешу.

Тестування Instant Navigations

Помічник instant() для Playwright дозволяє перевірити, який контент видимий одразу після навігації, без очікування мережі. Це виявляє регресії, де рефакторинг випадково уповільнює навігацію.

e2e/instant-navigation.spec.tstypescript
import { expect, test } from "@playwright/test"
import { instant } from "@next/playwright"

test("product title is available immediately", async ({ page }) => {
  await page.goto("/products/shoes")

  // Assert what's visible without waiting for network
  await instant(page, async () => {
    await page.click('a[href="/products/hats"]')
    await expect(page.locator("h1")).toContainText("Baseball Cap")
    await expect(page.getByText("Checking inventory...")).toBeVisible()
  })

  await expect(page.getByText("12 in stock")).toBeVisible()
})

Цей патерн гарантує, що сторінки, призначені для миттєвого завантаження, залишаються миттєвими після змін коду. Navigation Inspector у DevTools доповнює це, дозволяючи візуально інспектувати оболонки під час розробки.

Питання для співбесід: що запитують у senior-розробників

Ці питання відображають реальні патерни співбесід 2026 року для senior-позицій Next.js. Кожне спрямоване на конкретний аспект Cache Components та оновлень 16.3.

П1: Поясніть перехід від неявного до явного кешування в Next.js 16. Чому фреймворк зробив цю зміну?

Next.js 14-15 кешував виклики fetch та сторінки неявно. Налагодження того, чи є сторінка статичною чи динамічною, вимагало відстеження через кілька прихованих шарів кешу. Явна модель з "use cache" робить кешування видимим у вихідному коді. Компроміс: продуктивність може спочатку знизитися в застосунках, що мігрують з неявного кешування, але розробники отримують повний контроль та передбачуваність.

П2: Які три рівні "use cache" і коли слід використовувати кожен?

Рівень файлу для повністю статичних сторінок. Рівень компонента для змішування кешованого та динамічного контенту на сторінці (патерн PPR). Рівень функції для кешування конкретних операцій отримання даних. Вибір рівня визначає гранулярність кешу та межі інвалідації.

П3: Чим Partial Prefetching у 16.3 відрізняється від prefetching у 16.0?

У 16.0 Next.js надсилав запит prefetch для кожного посилання у видимій області. У 16.3 з partialPrefetching: true попередньо завантажується одна багаторазова оболонка на маршрут, кешована на стороні клієнта протягом сесії. Двадцять посилань на /chat/[id] викликають один prefetch для оболонки маршруту chat, а не двадцять окремих запитів. Це зменшує мережеве навантаження та узгоджується з тим, як SPA розділяють код.

П4: Команда кешує функцію, що повертає історію замовлень користувача, за допомогою "use cache". Що відбудеться?

Спільний кеш зберігає результат з ключем на основі аргументів функції. Якщо функція приймає параметр userId, різні користувачі отримують різні записи кешу, але інфраструктура кешу залишається спільною. Якщо функція читає userId з cookies() замість параметрів, збірка завершується помилкою, оскільки cookies() є runtime API, забороненим в обсязі спільного кешу. Розвʼязання: перейти на "use cache: private" або передати ідентифікатор користувача як явний аргумент.

П5: Чим cacheLife відрізняється від старого експорту revalidate?

revalidate була єдиним числом (секунди), що встановлювалося на рівні сторінки або layout. cacheLife використовує іменовані профілі з трьома вимірами: stale (подавати застарілий контент), revalidate (інтервал фонового оновлення) та expire (жорстке закінчення терміну). Профілі централізовані в next.config.ts, тому одна зміна впливає на всі місця виклику, що використовують цей профіль.

П6: Яка різниця між revalidateTag та updateTag?

Обидва інвалідують записи кешу за тегом. updateTag є рекомендованим примітивом у Next.js 16.3, розробленим для чистої інтеграції з явною моделлю кешування. На практиці обидва працюють для інвалідації за запитом, але updateTag є API, орієнтованим на майбутнє.

П7: Коли слід використовувати export const instant = false?

Коли маршрут має навмисно блокувати навігацію до відповіді сервера. Наприклад, блог може ніколи не показувати оболонку завантаження для постів, бажаючи, щоб читачі бачили повний контент одразу. Це вимикає помилки Instant Insights для цього маршруту.

Більше питань для співбесід з отримання даних у Next.js доступно на SharpSkill з практичними модулями, що включають сесії з таймером та детальні пояснення. Модуль Server Actions Next.js охоплює патерни Server Action, що працюють з інвалідацією кешу.

Практичний чек-лист для продакшн Cache Components

  • Увімкнення cacheComponents: true та partialPrefetching: true у next.config.ts
  • Аудит кожної сторінки: додавання "use cache" до статичних сторінок та функцій отримання даних, що обслуговують публічний контент
  • Огортання всього динамічного контенту (специфічного для користувача, часу запиту) в межі <Suspense> зі змістовними скелетними fallback
  • Використання "use cache: private" для кожної функції, що звертається до cookies, headers або повертає персоналізовані дані
  • Розгляд "use cache: remote" для даних з високим трафіком у безсерверних середовищах
  • Визначення користувацьких профілів cacheLife для типових категорій даних (дані продуктів, сесії користувачів, статичний контент)
  • Додавання cacheTag() до кожної кешованої функції, яка може потребувати інвалідації за запитом
  • Використання updateTag() для інвалідації за запитом у Server Actions
  • Тестування в продакшн режимі з next build && next start, оскільки поведінка кешування в next dev суттєво відрізняється
  • Написання тестів Playwright з instant() для виявлення регресій навігації
  • Використання Navigation Inspector у DevTools для візуалізації попередньо завантажених оболонок

Починай практикувати!

Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Джерела

Що запамʼятати про Cache Components у Next.js 16

  • Next.js 16 замінює неявне кешування явним "use cache" на рівні файлу, компонента та функції
  • Next.js 16.3 додає Instant Navigations: з partialPrefetching: true застосунки відчуваються такими ж швидкими, як SPA
  • PPR є стабільним під cacheComponents: true, доставляючи статичні оболонки з потоковим динамічним контентом
  • Профілі cacheLife замінюють revalidate централізованим, тривимірним контролем тривалості кешу
  • cacheTag + updateTag забезпечують інвалідацію за запитом; відсутні теги означають лише закінчення терміну за часом
  • "use cache: private" є обовʼязковим для даних, специфічних для користувача, щоб запобігти витоку даних між користувачами
  • "use cache: remote" допомагає безсерверним середовищам зберігати кеш між холодними стартами
  • Root params з next/root-params вирішують передачу props для глобальних динамічних сегментів, таких як [lang]
  • Питання на співбесідах 2026 року фокусуються на переході від неявного до явного кешування, Instant Navigations у 16.3, Partial Prefetching та безпеці кешу

Починай практикувати!

Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Щоденний виклик

Чи знайдеш ти помилку в React / Next.js?

Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Anthony Fillion-Maillet

Автор:

Anthony Fillion-Maillet

Засновник SharpSkill

Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.

Оновлено 25 серпня 2026 р.

Теги

#next.js
#react
#cache-components
#ppr
#interview

Поділитися

Пов'язані статті