spinny:~/writing $ vim nextjs-16-cache-components.md
1~2Протягом багатьох років одним із найбільш неприємних запитань у Next.js було: «Ця сторінка статична чи динамічна?». Це здається простим запитанням, доки ви не додасте виклик до `cookies()`, `fetch` з різними параметрами, клієнта бази даних, CMS, кошика для покупок або частини спеціального вмісту.3~4Next.js 16 цікавий тим, що він намагається зробити цю розмову менш загадковою. Це не усуває складності, але змінює ментальну модель: маршрути динамічні за замовчуванням, кеш оголошує себе там, де потрібно, а `Suspense` стає природним способом створення швидких оболонок із частинами, які залишаються свіжими.5~6Функція для розуміння — це компоненти кешу. Стабільний Turbopack, React Compiler, `proxy.ts` і нові API недійсності є важливими, але вони пов’язані з тією самою проблемою: створення швидких додатків без необхідності здогадуватися, що фреймворк вирішив за лаштунками.7~8## Тому що ця річ має значення9~10У реальному додатку ви маєте не лише «статичні» та «динамічні сторінки». У вас є різні предмети з різними потребами.11~12Аркуш товару може змінюватися кілька разів на день. Ціна може змінюватися частіше. Доступність має бути майже живою. Ім'я користувача персональне. Відгуки можна транслювати. Бічна панель може бути стійкою. Візок ні.13~14Якщо розглядати все як одне ціле, ви завжди потрапляєте в одну з двох крайнощів:15~16- агресивне кешування та ризик побачити старі дані;17- динамічний рендер скрізь і продуктивність нижча, ніж потрібно.18~19Компоненти кешу служать саме для того, щоб уникнути цього помилкового вибору.20~21## Модель на практиці22~23За допомогою `cacheComponents: true` ви можете оголосити те, що кешується, за допомогою `"use cache"`. Потім ви можете пов’язати тривалість і теги з `cacheLife()` і `cacheTag()`. Динамічні частини залишаються динамічними та можуть бути ізольовані за допомогою `Suspense`.24~25```mermaid26flowchart TD27 Request[Запит користувача] --> Shell[Кешована оболонка]28 Request --> Dynamic[Динамічні розділи]29 Shell --> FirstPaint[Перший швидкий контент]30 Dynamic --> Stream[Трансляція всередині саспенсу]31 Stream --> Complete[Повна сторінка]32```33~34Налаштування невелике:35~36```typescript37// next.config.ts38import type { NextConfig } from 'next';39~40const nextConfig: NextConfig = {41 cacheComponents: true,42};43~44export default nextConfig;45```46~47Велика зміна не в конфігурації. Справа в тому, як ви починаєте писати компоненти.48~49```tsx50// app/products/[slug]/page.tsx51import { Suspense } from 'react';52import { cacheLife, cacheTag } from 'next/cache';53~54async function getProduct(slug: string) {55 'use cache';56~57 cacheLife('hours');58 cacheTag(`product:${slug}`);59~60 return db.product.findUnique({ where: { slug } });61}62~63async function ProductDetails({ slug }: { slug: string }) {64 const product = await getProduct(slug);65~66 return (67 <section>68 <h1>{product.name}</h1>69 <p>{product.description}</p>70 </section>71 );72}73~74async function LiveInventory({ slug }: { slug: string }) {75 const inventory = await db.inventory.findFirst({ where: { slug } });76 return <p>{inventory.quantity} pezzi disponibili</p>;77}78~79export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {80 const { slug } = await params;81~82 return (83 <>84 <ProductDetails slug={slug} />85 <Suspense fallback={<p>Controllo disponibilità...</p>}>86 <LiveInventory slug={slug} />87 </Suspense>88 </>89 );90}91```92~93Сторінка не обов’язково має бути повністю кешованою або повністю динамічною. Аркуш продукту може бути швидким і багаторазовим. Інвентар може залишатися свіжим. Користувач бачить щось відразу, не чекаючи найповільнішої частини.94~95## `use cache` є виконуваною документацією96~97Мені подобається в `"use cache"` те, що він змушує вас чітко висловити намір. Коли читаєш функцію, одразу розумієш, що хтось вирішив: «ці дані можна повторно використовувати».98~99Це особливо корисно, коли ви не використовуєте `fetch`. Багато програм читають дані з Prisma, Drizzle, внутрішніх SDK, клієнтів CMS або сервісних функцій. У цих випадках старих міркувань, заснованих лише на `fetch` варіантах, було недостатньо.100~101Основне правило:102~103- вміст cachea відносно стабільний;104- використовувати гранульовані теги;105- залишає динамічні дозволи, сеанси, кошики, сповіщення та стани транзакцій;106- помістити повільні частини всередину `Suspense`;107- виміряти, перш ніж сказати "ми покращили продуктивність".108~109## Анулюйте, не викидаючи всього110~111Кеш корисний, лише якщо ви можете його точно оновити. Тут важливі `cacheTag`, `revalidateTag` і `updateTag`.112~113приклад:114~115```typescript116'use server';117~118import { updateTag } from 'next/cache';119~120export async function updateProductName(productId: string, name: string) {121 await db.product.update({122 where: { id: productId },123 data: { name },124 });125~126 updateTag(`product:${productId}`);127}128```129~130Важливою деталлю є тег. `product:${productId}` вказує точну межу. `products` розповідає величезне відро. Спочатку величезне відро зручно; через кілька місяців це стає причиною, через яку ви скасуєте половину програми, щоб змінити назву.131~132## Стабільний Turbopack: те, що ви чуєте щодня133~134Next.js 16 переносить Turbopack у центр розробки та створення. Це не найпоетичніша функція, але це та, яку ви відчуваєте під час роботи: сервер, який запускається раніше, швидше оновлення, збірки, які перестають відчувати себе як вимушена перерва на каву.135~136Тим не менш, я б не переніс кодову базу, повну нестандартних плагінів із заплющеними очима. Я б перевірив:137~138- місцева конструкція;139- нестандартний імпорт;140- MDX, SVG і CSS;141- Плагіни Webpack залишилися;142- критичні сторінки;143- відмінності в часі будівництва.144~145Для нових проектів я б почав із замовчуванням. Для зрілих я б зробив розмірену міграцію.146~147## Компілятор React: видалити шум, а не думку148~149Компілятор React 1.0 стабільний, а Next.js 16 підтримує його за допомогою `reactCompiler`. Обіцянка полягає в тому, щоб скоротити багато запам’ятовування вручну: менше `memo`, менше `useMemo`, менше `useCallback`, які використовуються «для безпеки».150~151```typescript152// next.config.ts153import type { NextConfig } from 'next';154~155const nextConfig: NextConfig = {156 reactCompiler: true,157};158~159export default nextConfig;160```161~162Я б не ставився до нього як до чарівного пилу. Компілятор допомагає, коли код добре дотримується правил React. Якщо компоненти мають дивні побічні ефекти, приховані мутації або погано використовувані хуки, це потрібно спочатку виправити.163~164Здоровий спосіб спробувати:165~1661. оновлення `eslint-plugin-react-hooks`;1672. фіксувати фактичні порушення;1683. включити його на контрольованій території;1694. виміряти час побудови та поведінку;1705. видалити ручне запам'ятовування лише тоді, коли воно більше не потрібно.171~172Мета полягає не в тому, щоб стерти кожен `useMemo`. Мета полягає в тому, щоб припинити писати превентивну мемоізацію, тому що ми боїмося рендерингу.173~174## `proxy.ts` та межі мережі175~176Старий `middleware.ts` стає `proxy.ts`. Це зміна назви, але це має сенс: цей файл знаходиться на межі запиту, це не традиційне базове проміжне програмне забезпечення.177~178```typescript179// proxy.ts180import { NextRequest, NextResponse } from 'next/server';181~182export default function proxy(request: NextRequest) {183 const isLoggedIn = Boolean(request.cookies.get('session'));184~185 if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) {186 return NextResponse.redirect(new URL('/login', request.url));187 }188~189 return NextResponse.next();190}191```192~193Правило тут просте: тримайте його маленьким. Перенаправлення, автентифікація маршрутизації, заголовки, основні перезаписи. Якщо він починає здаватися другим серверним модулем, ймовірно, він робить занадто багато.194~195## Як би я дійсно мігрував196~197Я б не став вмикати всі функції відразу. Я б зробив так:198~1991. Я оновлю Next, React і React DOM;2002. Я запускаю офіційний codemod;2013. Я виправляю критичні зміни в `params`, `searchParams`, `cookies()`, `headers()` та `draftMode()`;2024. Я переношу `middleware.ts` до `proxy.ts`;2035. Я перевіряю збірки та критичні сторінки;2046. Я вмикаю компоненти кешу в розділі, де кеш зараз створює тертя;2057. Я визначаю умови для тегів і недійсності;2068. Я пробую компілятор React окремо;2079. порівняння показників до і після.208~209Хороша міграція – це не та, у якій використовуються всі нові функції. Це те, що робить поведінку програми більш читабельною.210~211## Що змінюється в способі мислення212~213Найбільш корисним у Next.js 16 є те, що він змушує вас краще називати наміри. Функція — це не просто «отримати товар із бази даних». Це "отримайте продукт, я можу кешувати його годинами, я анулюю його цим тегом". Компонент – це не просто «відобразити сторінку». Це "це швидка оболонка, ця частина особиста, це транслюється".214~215Спочатку здається, що роботи більше. Тоді це стає формою спокою. Рішення щодо продуктивності більше не приховані в поєднанні стандартних значень, евристики та племінної пам’яті. Вони є в коді.216~217## Корисні джерела218~219- [Примітки до випуску Next.js 16](https://nextjs.org/blog/next-16)220- [Компоненти кешу - документи Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [використовувати кеш - документи Next.js](https://nextjs.org/docs/app/api-reference/directives/use-cache)222- [Компілятор React v1.0](https://react.dev/blog/2025/10/07/react-compiler-1)223~
NORMAL · nextjs-16-cache-components.md [readonly]223 lines · :q to close