NAME
nextjs-16-cache-components — Next.js 16, компоненти кешу та компілятор React: що насправді змінюється
SYNOPSIS
cat nextjs-16-cache-components.md
DESCRIPTION
Протягом багатьох років одним із найбільш неприємних запитань у Next.js було: «Ця сторінка статична чи динамічна?». Це здається простим запитанням, доки ви не додасте виклик до cookies(), fetch з різними параметрами, клієнта бази даних, CMS, кошика для покупок або частини спеціального вмісту.
Next.js 16 цікавий тим, що він намагається зробити цю розмову менш загадковою. Це не усуває складності, але змінює ментальну модель: маршрути динамічні за замовчуванням, кеш оголошує себе там, де потрібно, а Suspense стає природним способом створення швидких оболонок із частинами, які залишаються свіжими.
Функція для розуміння — це компоненти кешу. Стабільний Turbopack, React Compiler, proxy.ts і нові API недійсності є важливими, але вони пов’язані з тією самою проблемою: створення швидких додатків без необхідності здогадуватися, що фреймворк вирішив за лаштунками.
Тому що ця річ має значення
У реальному додатку ви маєте не лише «статичні» та «динамічні сторінки». У вас є різні предмети з різними потребами.
Аркуш товару може змінюватися кілька разів на день. Ціна може змінюватися частіше. Доступність має бути майже живою. Ім'я користувача персональне. Відгуки можна транслювати. Бічна панель може бути стійкою. Візок ні.
Якщо розглядати все як одне ціле, ви завжди потрапляєте в одну з двох крайнощів:
- агресивне кешування та ризик побачити старі дані;
- динамічний рендер скрізь і продуктивність нижча, ніж потрібно.
Компоненти кешу служать саме для того, щоб уникнути цього помилкового вибору.
Модель на практиці
За допомогою cacheComponents: true ви можете оголосити те, що кешується, за допомогою "use cache". Потім ви можете пов’язати тривалість і теги з cacheLife() і cacheTag(). Динамічні частини залишаються динамічними та можуть бути ізольовані за допомогою Suspense.
Налаштування невелике:
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { cacheComponents: true, }; export default nextConfig;
Велика зміна не в конфігурації. Справа в тому, як ви починаєте писати компоненти.
// app/products/[slug]/page.tsx import { Suspense } from 'react'; import { cacheLife, cacheTag } from 'next/cache'; async function getProduct(slug: string) { 'use cache'; cacheLife('hours'); cacheTag(`product:${slug}`); return db.product.findUnique({ where: { slug } }); } async function ProductDetails({ slug }: { slug: string }) { const product = await getProduct(slug); return ( <section> <h1>{product.name}</h1> <p>{product.description}</p> </section> ); } async function LiveInventory({ slug }: { slug: string }) { const inventory = await db.inventory.findFirst({ where: { slug } }); return <p>{inventory.quantity} pezzi disponibili</p>; } export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params; return ( <> <ProductDetails slug={slug} /> <Suspense fallback={<p>Controllo disponibilità...</p>}> <LiveInventory slug={slug} /> </Suspense> </> ); }
Сторінка не обов’язково має бути повністю кешованою або повністю динамічною. Аркуш продукту може бути швидким і багаторазовим. Інвентар може залишатися свіжим. Користувач бачить щось відразу, не чекаючи найповільнішої частини.
use cache є виконуваною документацією
Мені подобається в "use cache" те, що він змушує вас чітко висловити намір. Коли читаєш функцію, одразу розумієш, що хтось вирішив: «ці дані можна повторно використовувати».
Це особливо корисно, коли ви не використовуєте fetch. Багато програм читають дані з Prisma, Drizzle, внутрішніх SDK, клієнтів CMS або сервісних функцій. У цих випадках старих міркувань, заснованих лише на fetch варіантах, було недостатньо.
Основне правило:
- вміст cachea відносно стабільний;
- використовувати гранульовані теги;
- залишає динамічні дозволи, сеанси, кошики, сповіщення та стани транзакцій;
- помістити повільні частини всередину
Suspense; - виміряти, перш ніж сказати "ми покращили продуктивність".
Анулюйте, не викидаючи всього
Кеш корисний, лише якщо ви можете його точно оновити. Тут важливі cacheTag, revalidateTag і updateTag.
приклад:
'use server'; import { updateTag } from 'next/cache'; export async function updateProductName(productId: string, name: string) { await db.product.update({ where: { id: productId }, data: { name }, }); updateTag(`product:${productId}`); }
Важливою деталлю є тег. product:${productId} вказує точну межу. products розповідає величезне відро. Спочатку величезне відро зручно; через кілька місяців це стає причиною, через яку ви скасуєте половину програми, щоб змінити назву.
Стабільний Turbopack: те, що ви чуєте щодня
Next.js 16 переносить Turbopack у центр розробки та створення. Це не найпоетичніша функція, але це та, яку ви відчуваєте під час роботи: сервер, який запускається раніше, швидше оновлення, збірки, які перестають відчувати себе як вимушена перерва на каву.
Тим не менш, я б не переніс кодову базу, повну нестандартних плагінів із заплющеними очима. Я б перевірив:
- місцева конструкція;
- нестандартний імпорт;
- MDX, SVG і CSS;
- Плагіни Webpack залишилися;
- критичні сторінки;
- відмінності в часі будівництва.
Для нових проектів я б почав із замовчуванням. Для зрілих я б зробив розмірену міграцію.
Компілятор React: видалити шум, а не думку
Компілятор React 1.0 стабільний, а Next.js 16 підтримує його за допомогою reactCompiler. Обіцянка полягає в тому, щоб скоротити багато запам’ятовування вручну: менше memo, менше useMemo, менше useCallback, які використовуються «для безпеки».
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { reactCompiler: true, }; export default nextConfig;
Я б не ставився до нього як до чарівного пилу. Компілятор допомагає, коли код добре дотримується правил React. Якщо компоненти мають дивні побічні ефекти, приховані мутації або погано використовувані хуки, це потрібно спочатку виправити.
Здоровий спосіб спробувати:
- оновлення
eslint-plugin-react-hooks; - фіксувати фактичні порушення;
- включити його на контрольованій території;
- виміряти час побудови та поведінку;
- видалити ручне запам'ятовування лише тоді, коли воно більше не потрібно.
Мета полягає не в тому, щоб стерти кожен useMemo. Мета полягає в тому, щоб припинити писати превентивну мемоізацію, тому що ми боїмося рендерингу.
proxy.ts та межі мережі
Старий middleware.ts стає proxy.ts. Це зміна назви, але це має сенс: цей файл знаходиться на межі запиту, це не традиційне базове проміжне програмне забезпечення.
// proxy.ts import { NextRequest, NextResponse } from 'next/server'; export default function proxy(request: NextRequest) { const isLoggedIn = Boolean(request.cookies.get('session')); if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); }
Правило тут просте: тримайте його маленьким. Перенаправлення, автентифікація маршрутизації, заголовки, основні перезаписи. Якщо він починає здаватися другим серверним модулем, ймовірно, він робить занадто багато.
Як би я дійсно мігрував
Я б не став вмикати всі функції відразу. Я б зробив так:
- Я оновлю Next, React і React DOM;
- Я запускаю офіційний codemod;
- Я виправляю критичні зміни в
params,searchParams,cookies(),headers()таdraftMode(); - Я переношу
middleware.tsдоproxy.ts; - Я перевіряю збірки та критичні сторінки;
- Я вмикаю компоненти кешу в розділі, де кеш зараз створює тертя;
- Я визначаю умови для тегів і недійсності;
- Я пробую компілятор React окремо;
- порівняння показників до і після.
Хороша міграція – це не та, у якій використовуються всі нові функції. Це те, що робить поведінку програми більш читабельною.
Що змінюється в способі мислення
Найбільш корисним у Next.js 16 є те, що він змушує вас краще називати наміри. Функція — це не просто «отримати товар із бази даних». Це "отримайте продукт, я можу кешувати його годинами, я анулюю його цим тегом". Компонент – це не просто «відобразити сторінку». Це "це швидка оболонка, ця частина особиста, це транслюється".
Спочатку здається, що роботи більше. Тоді це стає формою спокою. Рішення щодо продуктивності більше не приховані в поєднанні стандартних значень, евристики та племінної пам’яті. Вони є в коді.
Корисні джерела
METADATA
- date: 2026-05-24
- reading: 6 min
- author: Filippo Spinella
- tags: Next.js, React, Frontend, Performance