NAME
nextjs-16-cache-components — Next.js 16, komponenty pamięci podręcznej i kompilator React: co naprawdę się zmienia
SYNOPSIS
cat nextjs-16-cache-components.md
DESCRIPTION
Przez lata jednym z najbardziej irytujących pytań w Next.js było: „Czy ta strona jest statyczna czy dynamiczna?”. Wydaje się to prostym pytaniem, dopóki nie dodasz wywołania do cookies(), fetch z różnymi opcjami, klienta bazy danych, CMS, koszyka lub fragmentu niestandardowej treści.
Next.js 16 jest interesujący, ponieważ stara się uczynić tę rozmowę mniej tajemniczą. Nie eliminuje to złożoności, ale zmienia model mentalny: trasy są domyślnie dynamiczne, pamięć podręczna deklaruje się tam, gdzie jest to potrzebne, a Suspense staje się naturalnym sposobem komponowania szybkich powłok z części, które pozostają świeże.
Cechą, którą należy zrozumieć, są komponenty pamięci podręcznej. Stable Turbopack, React Compiler, proxy.ts i nowe interfejsy API unieważniające są ważne, ale dotyczą tego samego problemu: tworzenia szybkich aplikacji bez konieczności zgadywania, co framework zdecydował za kulisami.
Ponieważ ta rzecz ma znaczenie
W prawdziwej aplikacji nie masz tylko „stron statycznych” i „stron dynamicznych”. Masz różne elementy i różne potrzeby.
Karta produktu może zmieniać się kilka razy dziennie. Cena może zmieniać się częściej. Dostępność musi być prawie aktywna. Nazwa użytkownika jest osobista. Recenzje można przesyłać strumieniowo. Pasek boczny może być stabilny. Wózek nie.
Jeśli potraktujesz wszystko jako jedną całość, zawsze znajdziesz się w jednej z dwóch skrajności:
- agresywne buforowanie i ryzyko zobaczenia starych danych;
- dynamiczne renderowanie wszędzie i wydajność gorsza niż to konieczne.
Cache Components służy właśnie do uniknięcia tego fałszywego wyboru.
Model w praktyce
Za pomocą cacheComponents: true możesz zadeklarować, co można buforować, używając "use cache". Następnie możesz powiązać czas trwania i znaczniki z cacheLife() i cacheTag(). Części dynamiczne pozostają dynamiczne i można je odizolować za pomocą Suspense.
Konfiguracja jest niewielka:
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { cacheComponents: true, }; export default nextConfig;
Duża zmiana nie dotyczy konfiguracji. Wszystko zależy od tego, jak zaczniesz pisać komponenty.
// 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> </> ); }
Strona nie musi być w całości buforowana ani dynamiczna. Karta produktu może być szybka i wielokrotnego użytku. Zapasy mogą pozostać świeże. Użytkownik widzi coś od razu, nie czekając na najwolniejszą część.
use cache to dokumentacja wykonywalna
To, co podoba mi się w "use cache", to to, że zmusza cię do wyraźnego wyrażenia swojej intencji. Kiedy czytasz funkcję, od razu rozumiesz, że ktoś zdecydował: „te dane można ponownie wykorzystać”.
Jest to szczególnie przydatne, gdy nie używasz fetch. Wiele aplikacji odczytuje dane z Prisma, Drizzle, wewnętrznych zestawów SDK, klientów CMS lub funkcji usługowych. W takich przypadkach stare rozumowanie oparte wyłącznie na opcjach fetch nie wystarczyło.
Praktyczna zasada:
- zawartość pamięci podręcznej stosunkowo stabilna;
- używaj szczegółowych tagów;
- pozostawia dynamiczne uprawnienia, sesje, koszyki, powiadomienia i stany transakcyjne;
- umieść powolne części wewnątrz
Suspense; - zmierzyć, zanim powiesz „poprawiliśmy wydajność”.
Unieważnij bez wyrzucania wszystkiego
Pamięć podręczna jest użyteczna tylko wtedy, gdy możesz ją dokładnie zaktualizować. Tutaj cacheTag, revalidateTag i updateTag stają się ważne.
Przykład:
'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}`); }
Ważnym szczegółem jest metka. product:${productId} wyznacza dokładną granicę. products mówi ogromnemu wiadro. Na początku ogromne wiadro jest wygodne; po kilku miesiącach staje się to powodem unieważnienia połowy aplikacji w celu zmiany tytułu.
Stabilny Turbopack: część, którą słyszysz każdego dnia
Next.js 16 przenosi Turbopack do centrum rozwoju i kompilacji. Nie jest to może najbardziej poetycka cecha, ale odczuwa się ją podczas pracy: serwer uruchamia się wcześniej, szybsze odświeżanie, kompilacje przestają przypominać wymuszoną przerwę na kawę.
To powiedziawszy, nie migrowałbym bazy kodu pełnej niestandardowych wtyczek z zamkniętymi oczami. sprawdziłbym:
- kompilacja lokalna;
- niestandardowe importy;
- MDX, SVG i CSS;
- Pozostały wtyczki pakietu internetowego;
- strony krytyczne;
- różnice w czasie budowy.
W przypadku nowych projektów zacząłbym od ustawień domyślnych. W przypadku dojrzałych przeprowadziłbym migrację odmierzoną.
React Compiler: usuń hałas, a nie myśl
React Compiler 1.0 jest stabilny, a Next.js 16 obsługuje go za pomocą reactCompiler. Obietnica polega na zmniejszeniu ilości ręcznego zapamiętywania: mniej memo, mniej useMemo, mniej useCallback używanych „dla bezpieczeństwa”.
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { reactCompiler: true, }; export default nextConfig;
Nie traktowałbym go jak magicznego pyłu. Kompilator pomaga, gdy kod jest zgodny z regułami React. Jeśli komponenty mają dziwne skutki uboczne, ukryte mutacje lub źle używane hooki, należy to najpierw naprawić.
Zdrowy sposób, aby spróbować:
- aktualizacja
eslint-plugin-react-hooks; - naprawić faktyczne naruszenia;
- włącz to na kontrolowanym obszarze;
- mierzyć czas i zachowanie kompilacji;
- usuwaj ręczne zapamiętywanie tylko wtedy, gdy nie jest już potrzebne.
Celem nie jest usunięcie każdego useMemo. Celem jest zaprzestanie pisania zapamiętywania zapobiegawczego, ponieważ boimy się renderowania.
proxy.ts i granicę sieci
Stary middleware.ts staje się proxy.ts. To zmiana nazwy, ale ma to sens: ten plik znajduje się na granicy żądania, a nie jest to tradycyjne, ogólne oprogramowanie pośredniczące w stylu backendu.
// 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(); }
Zasada jest tutaj prosta: trzymaj się małych rozmiarów. Przekierowanie, routing uwierzytelniania, nagłówki, niezbędne przeróbki. Jeśli zaczyna sprawiać wrażenie drugiego backendu, prawdopodobnie robi za dużo.
Jak naprawdę miałbym wyemigrować
Nie włączałbym wszystkich funkcji na raz. Zrobiłbym to:
- Aktualizuję Next, React i React DOM;
- Uruchamiam oficjalny codemod;
- Naprawiam istotne zmiany w
params,searchParams,cookies(),headers()idraftMode(); - Przeprowadzam migrację
middleware.tsdoproxy.ts; - Sprawdzam kompilacje i krytyczne strony;
- Włączam komponenty pamięci podręcznej w sekcji, w której pamięć podręczna powoduje obecnie tarcia;
- Definiuję konwencje dotyczące znaczników i unieważniania;
- Próbuję oddzielnie React Compiler;
- porównanie wskaźników przed i po.
Dobra migracja to nie ta, która wykorzystuje wszystkie nowe funkcje. To sprawia, że zachowanie aplikacji jest bardziej czytelne.
Co się zmienia w sposobie myślenia
Najbardziej użyteczną rzeczą w Next.js 16 jest to, że zmusza Cię do lepszego nazywania intencji. Funkcja to nie tylko „pobranie produktu z bazy danych”. To „zdobądź produkt, mogę go buforować godzinami, unieważniam go tym tagiem”. Komponent to nie tylko „renderowanie strony”. To „to jest szybka powłoka, ten utwór jest osobisty, to jest przesyłane strumieniowo”.
Na początku wydaje się, że jest więcej pracy. Wtedy staje się to formą spokoju. Decyzje dotyczące wydajności nie są już ukryte w kombinacji ustawień domyślnych, heurystyki i pamięci plemiennej. Są w kodzie.
Przydatne źródła
METADATA
- date: 2026-05-24
- reading: 6 min
- author: Filippo Spinella
- tags: Next.js, React, Frontend, Performance