Next.js 16, Cache Components at React Compiler: kung ano talaga ang nagbabago
· 8 min read · Filippo Spinella · Next.js, React, Frontend, Performance
Sa loob ng maraming taon, isa sa mga pinakanakakainis na tanong sa Next.js ay: "static o dynamic ba ang page na ito?". Tila isang simpleng tanong, hanggang sa magdagdag ka ng isang tawag sa cookies(), isang fetch na may iba't ibang opsyon, isang database client, isang CMS, isang shopping cart, o isang piraso ng custom na nilalaman.
Next.js 16 ay kawili-wili dahil sinusubukan nitong gawing mas misteryoso ang pag-uusap na ito. Hindi nito inaalis ang pagiging kumplikado, ngunit binabago nito ang modelo ng pag-iisip: ang mga ruta ay dynamic bilang default, ang cache ay nagdedeklara mismo kung saan kinakailangan, at ang Suspense ay nagiging natural na paraan upang bumuo ng mga mabilis na shell na may mga bahagi na nananatiling sariwa.
Ang feature na dapat maunawaan ay Cache Components. Ang Stable Turbopack, React Compiler, proxy.ts, at ang mga bagong invalidation API ay mahalaga, ngunit umiikot ang mga ito sa parehong problema: pagbuo ng mga mabilis na app nang hindi hinuhulaan kung ano ang napagpasyahan ng framework sa likod ng mga eksena.
Dahil ang bagay na ito ay mahalaga
Sa isang totoong app hindi lang "static page" at "dynamic page" ang mayroon ka. Mayroon kang iba't ibang piraso na may iba't ibang pangangailangan.
Ang sheet ng produkto ay maaaring magbago ng ilang beses sa isang araw. Ang presyo ay maaaring magbago nang mas madalas. Ang availability ay dapat na halos live. Ang username ay personal. Maaaring i-stream ang mga review. Ang sidebar ay maaaring maging matatag. Ang kariton ay hindi.
Kung ituturing mo ang lahat bilang isang yunit, palagi kang napupunta sa isa sa dalawang sukdulan:
- agresibong pag-cache at panganib na makakita ng lumang data;
- dynamic na pag-render sa lahat ng dako at mas masahol pa ang performance kaysa kinakailangan.
Eksaktong nagsisilbi ang Cache Components upang maiwasan ang maling pagpiling ito.
Ang modelo sa pagsasanay
Sa cacheComponents: true, maaari mong ideklara kung ano ang naka-cache gamit ang "use cache". Pagkatapos ay maaari mong iugnay ang tagal at mga tag sa cacheLife() at cacheTag(). Ang mga dynamic na bahagi ay nananatiling dynamic at maaaring ihiwalay sa Suspense.
Maliit ang setup:
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { cacheComponents: true, }; export default nextConfig;
Ang malaking pagbabago ay wala sa config. Nasa kung paano mo simulan ang pagsusulat ng mga bahagi.
// 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> </> ); }
Ang page ay hindi kailangang lahat ay naka-cache o lahat ay dynamic. Ang sheet ng produkto ay maaaring mabilis at magagamit muli. Maaaring manatiling sariwa ang imbentaryo. Nakikita kaagad ng user ang isang bagay, nang hindi naghihintay ng pinakamabagal na bahagi.
Ang use cache ay maipapatupad na dokumentasyon
Ang bagay na gusto ko tungkol sa "use cache" ay pinipilit ka nitong gawing tahasan ang isang intensyon. Kapag nagbasa ka ng isang function, naiintindihan mo kaagad na may nagpasya: "maaaring magamit muli ang data na ito".
Ito ay lalong kapaki-pakinabang kapag hindi mo ginagamit ang fetch. Maraming app ang nagbabasa ng data mula sa Prisma, Drizzle, internal SDKs, CMS client o service functions. Sa mga kasong iyon, hindi sapat ang lumang pangangatwiran batay lamang sa fetch na mga opsyon.
Isang tuntunin ng hinlalaki:
- medyo matatag ang nilalaman ng cachea;
- gumamit ng mga butil na tag;
- nag-iiwan ng mga dynamic na pahintulot, session, cart, notification at transactional na estado;
- ilagay ang mabagal na bahagi sa loob
Suspense; - sukatin bago sabihin ang "pinahusay namin ang pagganap".
Walang bisa nang hindi itinatapon ang lahat
Ang cache ay kapaki-pakinabang lamang kung maa-update mo ito nang tumpak. Dito nagiging mahalaga ang cacheTag, revalidateTag at updateTag.
Halimbawa:
'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}`); }
Ang mahalagang detalye ay ang tag. Ang product:${productId} ay nagsasabi ng isang tiyak na hangganan. products ay nagsasabi sa isang malaking balde. Sa una ang malaking balde ay komportable; pagkalipas ng ilang buwan ito ang nagiging dahilan kung bakit hindi mo wasto ang kalahati ng isang app para magpalit ng pamagat.
Stable Turbopack: ang bahaging naririnig mo araw-araw
Dinadala ng Next.js 16 ang Turbopack sa sentro para sa pag-unlad at pagbuo. Hindi ito ang pinaka-mapatula na tampok, ngunit ito ang nararamdaman mo habang nagtatrabaho ka: server na nagsisimula nang mas maaga, mas mabilis na pag-refresh, bubuo na humihinto sa pakiramdam na parang sapilitang coffee break.
Sabi nga, hindi ako maglilipat ng codebase na puno ng mga custom na plugin nang nakapikit. Susuriin ko:
- lokal na pagtatayo;
- hindi karaniwang pag-import;
- MDX, SVG at CSS;
- Naiwan ang mga plugin ng Webpack;
- kritikal na mga pahina;
- mga pagkakaiba sa oras ng pagtatayo.
Para sa mga bagong proyekto, magsisimula ako sa default. Para sa mga mature, gagawa ako ng sinukat na paglipat.
React Compiler: alisin ang ingay, hindi naisip
Ang React Compiler 1.0 ay stable at ang Next.js 16 ay sinusuportahan ito ng reactCompiler. Ang pangako ay bawasan ang maraming manu-manong memoization: mas kaunti ang memo, mas kaunti ang useMemo, mas kaunti ang useCallback na ginamit "para sa kaligtasan."
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { reactCompiler: true, }; export default nextConfig;
Hindi ko ito ituturing na parang magic dust. Nakakatulong ang compiler kapag sinusunod ng code ang mga panuntunan ng React. Kung ang mga sangkap ay may kakaibang epekto, mga nakatagong mutasyon o hindi wastong paggamit ng mga kawit, kailangan muna itong ayusin.
Ang malusog na paraan upang subukan ito:
- update
eslint-plugin-react-hooks; - ayusin ang mga aktwal na paglabag;
- paganahin ito sa isang kontroladong lugar;
- sukatin ang oras ng pagbuo at pag-uugali;
- alisin lang ang manual memoization kapag hindi na ito kailangan.
Ang layunin ay hindi burahin ang bawat useMemo. Ang layunin ay ihinto ang pagsusulat ng preventive memoization dahil natatakot kaming mag-render.
proxy.ts at ang hangganan ng network
Ang lumang middleware.ts ay nagiging proxy.ts. Ito ay isang pagpapalit ng pangalan, ngunit makatuwiran: ang file na iyon ay nasa hangganan ng kahilingan, hindi ito tradisyonal na backend-style na generic na middleware.
// 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(); }
Ang panuntunan dito ay simple: panatilihin itong maliit. I-redirect, auth routing, mga header, mahahalagang rewrite. Kung magsisimula itong pakiramdam na parang pangalawang backend, malamang na sobra ang ginagawa nito.
Kung paano talaga ako magmigrate
Hindi ko i-on ang lahat ng feature nang sabay-sabay. Gagawin ko ito:
- Ina-update ko ang Next, React at React DOM;
- Inilunsad ko ang opisyal na codemod;
- Inaayos ko ang mga nasira na pagbabago sa
params,searchParams,cookies(),headers()atdraftMode(); - Lumipat ako ng
middleware.tssaproxy.ts; - Sinusuri ko ang mga build at kritikal na pahina;
- Pinagana ko ang Mga Bahagi ng Cache sa isang seksyon kung saan ang cache ay kasalukuyang lumilikha ng friction;
- Tinutukoy ko ang mga kumbensyon para sa mga tag at kawalan ng bisa;
- Sinusubukan kong hiwalay ang React Compiler;
- paghahambing ng mga sukatan bago at pagkatapos.
Ang magandang paglipat ay hindi ang isa na gumagamit ng lahat ng mga bagong tampok. Ito ang dahilan kung bakit mas nababasa ang gawi ng app.
Ano ang nagbabago sa paraan ng pag-iisip
Ang pinakakapaki-pakinabang na bagay tungkol sa Next.js 16 ay pinipilit ka nitong pangalanan ang mga intensyon nang mas mahusay. Ang isang function ay hindi lamang "kunin ang produkto mula sa database". Ito ay "kunin ang produkto, maaari ko itong i-cache nang maraming oras, pinawalang-bisa ko ito sa tag na ito". Ang isang bahagi ay hindi lamang "i-render ang pahina". Ito ay "ito ang mabilis na shell, ang piraso na ito ay personal, ito ay dumarating sa streaming."
Sa una parang mas maraming trabaho. Pagkatapos ito ay nagiging isang anyo ng kalmado. Ang mga pagpapasya sa pagganap ay hindi na nakatago sa isang kumbinasyon ng mga default, heuristics at memorya ng tribo. Nasa code sila.