spinny:~/writing $ less nextjs-16-cache-components.md
12หลายปีที่ผ่านมาหนึ่งในคำถามที่น่ารำคาญที่สุดใน Next.js คือ: "หน้านี้เป็นแบบคงที่หรือไดนามิก" ดูเหมือนเป็นคำถามง่ายๆ จนกว่าคุณจะเพิ่มการเรียก `cookies()`, `fetch` ที่มีตัวเลือกต่างๆ, ไคลเอนต์ฐานข้อมูล, CMS, ตะกร้าสินค้า หรือเนื้อหาที่กำหนดเอง34Next.js 16 น่าสนใจเพราะพยายามทำให้การสนทนานี้ลึกลับน้อยลง มันไม่ได้ขจัดความซับซ้อน แต่มันเปลี่ยนโมเดลทางจิต: เส้นทางเป็นไดนามิกตามค่าเริ่มต้น แคชจะประกาศตัวเองเมื่อจำเป็น และ `Suspense` กลายเป็นวิธีธรรมชาติในการเขียนเชลล์ที่รวดเร็วด้วยชิ้นส่วนที่ยังคงความสดใหม่56คุณลักษณะที่ต้องทำความเข้าใจคือส่วนประกอบแคช Turbopack ที่เสถียร, React Compiler, `proxy.ts` และ API ที่ทำให้ใช้งานไม่ได้ใหม่มีความสำคัญ แต่สิ่งเหล่านี้เกี่ยวข้องกับปัญหาเดียวกัน นั่นคือ การสร้างแอปที่รวดเร็วโดยไม่ต้องเดาว่าเฟรมเวิร์กตัดสินใจอะไรอยู่เบื้องหลัง78## เพราะสิ่งนี้สำคัญ910ในแอปจริง คุณไม่ได้มีแค่ "หน้าคงที่" และ "หน้าไดนามิก" เท่านั้น คุณมีชิ้นส่วนที่แตกต่างกันและมีความต้องการที่แตกต่างกัน1112แผ่นผลิตภัณฑ์อาจมีการเปลี่ยนแปลงสองครั้งต่อวัน ราคาอาจมีการเปลี่ยนแปลงบ่อยขึ้น ความพร้อมใช้งานจะต้องเกือบจะใช้งานได้จริง ชื่อผู้ใช้เป็นเรื่องส่วนตัว สามารถสตรีมรีวิวได้ แถบด้านข้างสามารถมีเสถียรภาพได้ รถเข็นไม่ได้.1314หากคุณปฏิบัติต่อทุกสิ่งทุกอย่างเป็นหนึ่งเดียว คุณจะจบลงด้วยหนึ่งในสองภาวะสุดโต่งเสมอ:1516- การแคชเชิงรุกและความเสี่ยงในการดูข้อมูลเก่า17- การเรนเดอร์แบบไดนามิกทุกที่และประสิทธิภาพแย่เกินความจำเป็น1819ส่วนประกอบแคชทำหน้าที่อย่างแม่นยำเพื่อหลีกเลี่ยงตัวเลือกที่ผิดพลาดนี้2021## แบบอย่างในทางปฏิบัติ2223ด้วย `cacheComponents: true` คุณสามารถประกาศสิ่งที่แคชได้โดยใช้ `"use cache"` จากนั้น คุณสามารถเชื่อมโยงระยะเวลาและแท็กกับ `cacheLife()` และ `cacheTag()` ได้ ส่วนไดนามิกจะยังคงไดนามิกและสามารถแยกได้ด้วย `Suspense`2425```mermaid26flowchart TD27 Request[คำขอของผู้ใช้] --> Shell[เชลล์แคช]28 Request --> Dynamic[ส่วนไดนามิก]29 Shell --> FirstPaint[เนื้อหาด่วนครั้งแรก]30 Dynamic --> Stream[สตรีมมิ่งภายในใจจดใจจ่อ]31 Stream --> Complete[หน้าเต็ม]32```3334การตั้งค่ามีขนาดเล็ก:3536```typescript37// next.config.ts38import type { NextConfig } from 'next';3940const nextConfig: NextConfig = {41 cacheComponents: true,42};4344export default nextConfig;45```4647การเปลี่ยนแปลงครั้งใหญ่ไม่ได้อยู่ในการกำหนดค่า มันอยู่ที่คุณเริ่มเขียนส่วนประกอบอย่างไร4849```tsx50// app/products/[slug]/page.tsx51import { Suspense } from 'react';52import { cacheLife, cacheTag } from 'next/cache';5354async function getProduct(slug: string) {55 'use cache';5657 cacheLife('hours');58 cacheTag(`product:${slug}`);5960 return db.product.findUnique({ where: { slug } });61}6263async function ProductDetails({ slug }: { slug: string }) {64 const product = await getProduct(slug);6566 return (67 <section>68 <h1>{product.name}</h1>69 <p>{product.description}</p>70 </section>71 );72}7374async function LiveInventory({ slug }: { slug: string }) {75 const inventory = await db.inventory.findFirst({ where: { slug } });76 return <p>{inventory.quantity} pezzi disponibili</p>;77}7879export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {80 const { slug } = await params;8182 return (83 <>84 <ProductDetails slug={slug} />85 <Suspense fallback={<p>Controllo disponibilità...</p>}>86 <LiveInventory slug={slug} />87 </Suspense>88 </>89 );90}91```9293หน้านี้ไม่จำเป็นต้องแคชทั้งหมดหรือไดนามิกทั้งหมด แผ่นผลิตภัณฑ์สามารถใช้งานได้รวดเร็วและนำกลับมาใช้ใหม่ได้ สินค้าคงคลังสามารถคงความสดได้ ผู้ใช้มองเห็นบางสิ่งบางอย่างได้ทันทีโดยไม่ต้องรอส่วนที่ช้าที่สุด9495## `use cache` เป็นเอกสารปฏิบัติการ9697สิ่งที่ฉันชอบเกี่ยวกับ `"use cache"` ก็คือมันบังคับให้คุณแสดงเจตนาอย่างชัดเจน เมื่อคุณอ่านฟังก์ชัน คุณจะเข้าใจทันทีว่ามีคนตัดสินใจว่า "ข้อมูลนี้สามารถนำมาใช้ซ้ำได้"9899ซึ่งจะมีประโยชน์อย่างยิ่งเมื่อคุณไม่ได้ใช้ `fetch` แอพจำนวนมากอ่านข้อมูลจาก Prisma, Drizzle, SDK ภายใน, ไคลเอนต์ CMS หรือฟังก์ชั่นบริการ ในกรณีเหล่านั้น การใช้เหตุผลแบบเก่าตามตัวเลือก `fetch` เท่านั้นยังไม่เพียงพอ100101กฎง่ายๆ:102103- เนื้อหาแคชค่อนข้างเสถียร104- ใช้แท็กแบบละเอียด105- ออกจากสิทธิ์แบบไดนามิก เซสชัน รถเข็น การแจ้งเตือน และสถานะธุรกรรม106- ใส่ส่วนที่ช้าเข้าไปข้างใน `Suspense`;107- วัดผลก่อนที่จะพูดว่า "เราปรับปรุงประสิทธิภาพ"108109## ทำให้เป็นโมฆะโดยไม่ต้องทิ้งทุกสิ่งทุกอย่าง110111แคชจะมีประโยชน์ก็ต่อเมื่อคุณสามารถอัปเดตได้อย่างถูกต้อง ที่นี่ `cacheTag`, `revalidateTag` และ `updateTag` มีความสำคัญ112113ตัวอย่าง:114115```typescript116'use server';117118import { updateTag } from 'next/cache';119120export async function updateProductName(productId: string, name: string) {121 await db.product.update({122 where: { id: productId },123 data: { name },124 });125126 updateTag(`product:${productId}`);127}128```129130รายละเอียดที่สำคัญคือแท็ก `product:${productId}` บอกขอบเขตที่ชัดเจน `products` บอกถังขนาดใหญ่ ในตอนแรกถังขนาดใหญ่ก็สบาย หลังจากผ่านไปไม่กี่เดือน เหตุผลก็คือคุณทำให้แอปครึ่งหนึ่งไม่สามารถเปลี่ยนชื่อได้131132## Stable Turbopack: ส่วนที่คุณได้ยินทุกวัน133134Next.js 16 นำ Turbopack มาสู่ศูนย์กลางสำหรับการพัฒนาและการสร้าง มันไม่ใช่ฟีเจอร์ที่ไพเราะที่สุด แต่เป็นฟีเจอร์ที่คุณรู้สึกได้ในขณะทำงาน: เซิร์ฟเวอร์ที่เริ่มทำงานเร็วขึ้น รีเฟรชเร็วขึ้น สร้างที่หยุดรู้สึกเหมือนต้องพักดื่มกาแฟ135136อย่างที่กล่าวไปแล้ว ฉันจะไม่ย้ายฐานโค้ดที่เต็มไปด้วยปลั๊กอินแบบกำหนดเองโดยที่หลับตา ฉันจะตรวจสอบ:137138- งานสร้างในท้องถิ่น139- การนำเข้าที่ไม่ได้มาตรฐาน140- MDX, SVG และ CSS;141- เหลือปลั๊กอิน Webpack;142- หน้าที่สำคัญ143- ความแตกต่างในเวลาสร้าง144145สำหรับโปรเจ็กต์ใหม่ ฉันจะเริ่มจากค่าเริ่มต้น สำหรับผู้ใหญ่ ฉันจะทำการโยกย้ายแบบวัดผล146147## React Compiler: ลบเสียงรบกวน ไม่ใช่ความคิด148149React Compiler 1.0 มีความเสถียร และ Next.js 16 รองรับด้วย `reactCompiler` คำมั่นสัญญาคือจะลดการจดจำด้วยตนเองให้น้อยลง: `memo` น้อยลง, `useMemo` น้อยลง, `useCallback` น้อยลง ใช้ "เพื่อความปลอดภัย"150151```typescript152// next.config.ts153import type { NextConfig } from 'next';154155const nextConfig: NextConfig = {156 reactCompiler: true,157};158159export default nextConfig;160```161162ฉันจะไม่ปฏิบัติต่อมันเหมือนฝุ่นวิเศษ คอมไพเลอร์จะช่วยเมื่อโค้ดเป็นไปตามกฎ React อย่างดี หากส่วนประกอบมีผลข้างเคียงแปลกๆ การกลายพันธุ์ที่ซ่อนอยู่ หรือมีการใช้งานที่ไม่ดี จะต้องได้รับการแก้ไขก่อน163164วิธีที่ดีต่อสุขภาพที่ควรลอง:1651661. อัปเดต `eslint-plugin-react-hooks`;1672. แก้ไขการละเมิดที่เกิดขึ้นจริง1683. เปิดใช้งานบนพื้นที่ควบคุม1694. วัดเวลาและพฤติกรรมในการสร้าง1705. ลบการจดจำด้วยตนเองเฉพาะเมื่อไม่ต้องการอีกต่อไป171172เป้าหมายไม่ใช่การลบทุกๆ `useMemo` เป้าหมายคือการหยุดเขียนบันทึกเชิงป้องกันเพราะเรากลัวการแสดงผล173174## `proxy.ts` และขอบเขตเครือข่าย175176`middleware.ts` แบบเก่าจะกลายเป็น `proxy.ts` เป็นการเปลี่ยนชื่อ แต่ก็สมเหตุสมผลแล้ว: ไฟล์นั้นอยู่ที่ขอบเขตคำขอ ไม่ใช่มิดเดิลแวร์ทั่วไปแบบแบ็กเอนด์แบบดั้งเดิม177178```typescript179// proxy.ts180import { NextRequest, NextResponse } from 'next/server';181182export default function proxy(request: NextRequest) {183 const isLoggedIn = Boolean(request.cookies.get('session'));184185 if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) {186 return NextResponse.redirect(new URL('/login', request.url));187 }188189 return NextResponse.next();190}191```192193กฎง่ายๆ ที่นี่: ทำให้มันเล็ก การเปลี่ยนเส้นทาง การกำหนดเส้นทางการรับรองความถูกต้อง ส่วนหัว การเขียนใหม่ที่จำเป็น ถ้ามันเริ่มรู้สึกเหมือนเป็นแบ็กเอนด์ที่สอง มันอาจจะทำมากเกินไป194195## ฉันจะย้ายถิ่นฐานได้อย่างไร196197ฉันจะไม่เปิดคุณสมบัติทั้งหมดพร้อมกัน ฉันจะทำสิ่งนี้:1981991. ฉันอัปเดต Next, React และ React DOM;2002. ฉันเปิดตัว codemod อย่างเป็นทางการ2013. ฉันแก้ไขการเปลี่ยนแปลงที่เสียหายใน `params`, `searchParams`, `cookies()`, `headers()` และ `draftMode()`;2024. ฉันย้าย `middleware.ts` ไปที่ `proxy.ts`;2035. ฉันตรวจสอบบิลด์และเพจที่สำคัญ2046. ฉันเปิดใช้งานส่วนประกอบแคชในส่วนที่แคชสร้างความขัดแย้งในปัจจุบัน2057. ฉันกำหนดแบบแผนสำหรับแท็กและการทำให้ใช้ไม่ได้2068. ฉันลองใช้ React Compiler แยกกัน2079. การเปรียบเทียบตัวชี้วัดก่อนและหลัง208209การโยกย้ายที่ดีไม่ใช่การโยกย้ายที่ใช้คุณสมบัติใหม่ทั้งหมด เป็นสิ่งที่ทำให้พฤติกรรมของแอปอ่านง่ายขึ้น210211## สิ่งที่เปลี่ยนแปลงไปในวิธีคิด212213สิ่งที่มีประโยชน์ที่สุดเกี่ยวกับ Next.js 16 คือมันบังคับให้คุณตั้งชื่อความตั้งใจได้ดีขึ้น ฟังก์ชันไม่ใช่แค่ "รับผลิตภัณฑ์จากฐานข้อมูล" เท่านั้น มันขึ้นว่า "รับสินค้า ฉันสามารถแคชได้เป็นชั่วโมง ฉันทำให้สินค้าใช้งานไม่ได้ด้วยแท็กนี้" ส่วนประกอบไม่ได้เป็นเพียง "เรนเดอร์เพจ" เท่านั้น มันคือ "นี่คือสิ่งที่รวดเร็ว งานชิ้นนี้เป็นเรื่องส่วนตัว และมาพร้อมกับการสตรีม"214215ตอนแรกเหมือนจะมีงานมากขึ้น แล้วมันจะกลายเป็นความสงบ การตัดสินใจด้านประสิทธิภาพจะไม่ถูกซ่อนอยู่ในการผสมผสานระหว่างค่าเริ่มต้น การวิเคราะห์พฤติกรรม และความทรงจำของชนเผ่าอีกต่อไป พวกเขาอยู่ในรหัส216217## แหล่งข้อมูลที่เป็นประโยชน์218219- [บันทึกประจำรุ่น 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- [รีแอคคอมไพเลอร์ v1.0](https://react.dev/blog/2025/10/07/react-compiler-1)223
:Next.js 16, Cache Components และ React Compiler: สิ่งที่เปลี่ยนแปลงไปจริงๆlines 1-223 (END) — press q to close