Cache Components ใน Next.js 16 ปี 2026: คู่มือครบถ้วน use cache, PPR และคำถามสัมภาษณ์งาน
คู่มือเชิงลึกเกี่ยวกับ Cache Components ใน Next.js 16: directive use cache ทั้งสามระดับ, Partial Pre-Rendering, cacheLife profiles, cacheTag, ความปลอดภัยของ cache และคำถามสัมภาษณ์งานสำหรับ developer ในปี 2026

Next.js 16 Cache Components เปลี่ยนแนวคิดพื้นฐานของการจัดการ cache ใน Next.js อย่างสิ้นเชิง โมเดลเดิมใช้หลักการ cache ทุกอย่างโดยอัตโนมัติและต้อง opt-out เมื่อไม่ต้องการ แต่โมเดลใหม่ใช้หลักการไม่ cache อะไรเลยโดยอัตโนมัติและต้อง opt-in ด้วย directive "use cache" เมื่อต้องการ cache การเปลี่ยนแปลงครั้งนี้ถือเป็นการปรับปรุงครั้งใหญ่ที่สุดในระบบ caching ของ Next.js นับตั้งแต่เปิดตัว App Router
การเปลี่ยนแปลงนี้มีผลกระทบโดยตรงต่อการพัฒนาแอปพลิเคชันและยังเป็นหัวข้อที่ถูกถามบ่อยใน next.js 16 interview questions สำหรับตำแหน่งนักพัฒนา Frontend และ Full-stack ในปี 2026
Next.js 16 เปลี่ยนจาก caching แบบอัตโนมัติ (cache ทุกอย่าง ต้อง opt-out ด้วย dynamic APIs) เป็น caching แบบชัดเจน (ไม่ cache อะไรเลย ต้อง opt-in ด้วย "use cache") การเปลี่ยนแปลงนี้ส่งผลต่อ routing, data fetching, rendering และรูปแบบคำถามสัมภาษณ์งาน
เหตุผลที่ Next.js 16 เลิกใช้ Implicit Caching
ใน Next.js 15 และเวอร์ชันก่อนหน้า ทุก fetch() request ถูก cache โดยอัตโนมัติ นักพัฒนาต้องใช้ cache: 'no-store' หรือ revalidate: 0 เพื่อปิดการ cache พฤติกรรมนี้สร้างความสับสนอย่างมาก เนื่องจากนักพัฒนามักจะลืมว่าข้อมูลถูก cache อยู่ ทำให้แอปพลิเคชันแสดงข้อมูลเก่าโดยไม่ได้ตั้งใจ
ปัญหาที่พบบ่อยในโมเดลเดิม:
- ข้อมูลแสดงไม่ถูกต้องเนื่องจาก cache ที่ไม่ได้ตั้งใจ
- การ debug ยากลำบากเพราะไม่แน่ใจว่าข้อมูลมาจาก cache หรือ fetch ใหม่
- การจัดการ cache invalidation ซับซ้อนและมีข้อผิดพลาดง่าย
- ความปลอดภัยของข้อมูลเสี่ยงเมื่อข้อมูลส่วนบุคคลถูก cache โดยไม่ตั้งใจ
Next.js 16 แก้ปัญหาเหล่านี้ด้วยการเปลี่ยนค่าเริ่มต้นให้ไม่ cache อะไรเลย นักพัฒนาต้องประกาศอย่างชัดเจนว่าต้องการ cache ส่วนไหนของแอปพลิเคชัน แนวคิดนี้เรียกว่า cache components next.js และเป็นหัวใจสำคัญของระบบ caching ใหม่
วิธีการทำงานของ use cache Directive ในสามระดับ
Directive "use cache" สามารถใช้ได้ในสามระดับ: ระดับไฟล์ ระดับ component และระดับ function แต่ละระดับมีขอบเขตและกรณีใช้งานที่แตกต่างกัน
ระดับไฟล์ (File-level Caching)
เมื่อวาง "use cache" ที่ด้านบนสุดของไฟล์ ทุกส่วนของไฟล์นั้นจะถูก cache รวมถึง component และ function ทั้งหมดที่ export ออกไป
"use cache"
import { getPricingPlans } from "@/lib/data"
// Entire page is cached as a static shell
export default async function PricingPage() {
const plans = await getPricingPlans()
return (
<section>
{plans.map((plan) => (
<PricingCard key={plan.id} plan={plan} />
))}
</section>
)
}การใช้งานระดับไฟล์เหมาะสำหรับหน้าที่มีเนื้อหาคงที่หรือเปลี่ยนแปลงไม่บ่อย เช่น หน้าราคา หน้าเกี่ยวกับบริษัท หรือหน้า landing page
ระดับ Component (Component-level Caching)
สำหรับกรณีที่ต้องการ cache เฉพาะบาง component ในหน้าเดียวกัน สามารถวาง directive ภายใน component function ได้โดยตรง
async function ProductRecommendations({ categoryId }: { categoryId: string }) {
"use cache"
// categoryId becomes part of the automatic cache key
const products = await getTopProducts(categoryId)
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name} - {p.price}</li>
))}
</ul>
)
}สิ่งสำคัญที่ควรทราบคือ props ทั้งหมดที่ส่งเข้ามา (เช่น categoryId) จะถูกรวมเป็นส่วนหนึ่งของ cache key โดยอัตโนมัติ ซึ่งหมายความว่า category ที่แตกต่างกันจะมี cache แยกกัน
ระดับ Function (Function-level Caching)
สำหรับ data fetching function ที่ถูกเรียกใช้จากหลายที่ การ cache ที่ระดับ function ช่วยให้ทุกการเรียกใช้ได้รับประโยชน์จาก cache เดียวกัน
import { cacheLife } from "next/cache"
export async function getArticleBySlug(slug: string) {
"use cache"
cacheLife("hours")
// slug is automatically included in the cache key
const article = await db.article.findUnique({ where: { slug } })
return article
}เริ่มต้นจากระดับ function สำหรับ data fetching logic จากนั้นพิจารณาระดับ component สำหรับ UI ที่มีการดึงข้อมูล และใช้ระดับไฟล์เฉพาะหน้าที่มีเนื้อหาคงที่ทั้งหมด
Partial Pre-Rendering: Static Shell พร้อม Dynamic Holes
Partial Pre-Rendering หรือ PPR เป็นฟีเจอร์ที่ทำงานร่วมกับ cache components next.js อย่างลงตัว แนวคิดของ partial pre-rendering คือการแบ่งหน้าออกเป็นสองส่วน: static shell ที่ถูก pre-render และส่งทันที กับ dynamic holes ที่ถูก stream เข้ามาทีหลัง
import { Suspense } from "react"
import { UserGreeting } from "@/components/UserGreeting"
import { StaticSidebar } from "@/components/StaticSidebar"
import { RecentActivity } from "@/components/RecentActivity"
export default function DashboardPage() {
return (
<div className="grid grid-cols-12 gap-6">
{/* Cached static shell - served instantly */}
<StaticSidebar />
<main className="col-span-9">
{/* Dynamic - streams in after static shell */}
<Suspense fallback={<GreetingSkeleton />}>
<UserGreeting />
</Suspense>
{/* Dynamic - streams independently */}
<Suspense fallback={<ActivitySkeleton />}>
<RecentActivity />
</Suspense>
</main>
</div>
)
}ในตัวอย่างนี้ StaticSidebar ถูก cache และส่งถึงผู้ใช้ทันที ในขณะที่ UserGreeting และ RecentActivity ซึ่งต้องการข้อมูลเฉพาะผู้ใช้จะถูก stream เข้ามาทีหลังโดยไม่ block การแสดงผล static shell
ข้อดีของ partial pre-rendering:
- Time to First Byte (TTFB) ต่ำมากเนื่องจาก static shell ถูกส่งทันที
- ผู้ใช้เห็นโครงสร้างหน้าทันทีแม้ข้อมูล dynamic ยังไม่พร้อม
- แต่ละ Suspense boundary stream อิสระจากกัน
- SEO ได้รับประโยชน์จาก static content ที่ crawler เห็นทันที
เพิ่ม cacheComponents: true ใน next.config.ts flag เดียวนี้เปิดใช้งาน PPR, directive "use cache" และระบบ Cache Components ทั้งหมด ไม่จำเป็นต้องตั้งค่าเพิ่มเติม
cacheLife Profiles: แทนที่ระบบ revalidate เดิม
ใน Next.js 15 การกำหนดเวลา revalidation ใช้ตัวเลขวินาทีโดยตรง เช่น revalidate: 3600 แต่ใน Next.js 16 ระบบ cacheLife ใช้ profile ที่มีชื่อเรียกชัดเจน ทำให้โค้ดอ่านง่ายและจัดการได้สะดวกกว่า
import { cacheLife } from "next/cache"
export async function getExchangeRates() {
"use cache"
cacheLife("minutes") // Revalidates every few minutes
const rates = await fetch("https://api.exchangerate.host/latest")
return rates.json()
}
export async function getCompanyInfo() {
"use cache"
cacheLife("weeks") // Rarely changes
return db.company.findFirst()
}Next.js 16 มาพร้อม built-in profiles ดังนี้:
"seconds"- cache สั้นมาก สำหรับข้อมูลที่เปลี่ยนเร็ว"minutes"- cache ไม่กี่นาที สำหรับข้อมูลที่ต้อง fresh พอสมควร"hours"- cache หลายชั่วโมง สำหรับข้อมูลที่เปลี่ยนไม่บ่อย"days"- cache หลายวัน สำหรับข้อมูลที่ค่อนข้างคงที่"weeks"- cache นาน สำหรับข้อมูลที่แทบไม่เปลี่ยน"max"- cache นานที่สุดที่เป็นไปได้
การสร้าง Custom cacheLife Profile
สำหรับกรณีที่ built-in profiles ไม่ตรงกับความต้องการ สามารถสร้าง custom profile ใน next.config.ts ได้
import type { NextConfig } from "next"
const config: NextConfig = {
cacheComponents: true,
cacheLife: {
// Custom profile for product data
product: {
stale: 300, // Serve stale for 5 minutes
revalidate: 3600, // Revalidate in background every hour
expire: 86400, // Hard expire after 24 hours
},
},
}
export default configการตั้งค่า custom profile ประกอบด้วยสามส่วน:
stale- ระยะเวลาที่ยอมให้ serve ข้อมูลเก่าได้ (หน่วยวินาที)revalidate- ความถี่ในการ revalidate เบื้องหลังexpire- เวลาที่ cache หมดอายุอย่างถาวร
การใช้ cacheLife แบบมีเงื่อนไข
ฟีเจอร์ที่มีประโยชน์มากคือการกำหนด cacheLife แบบมีเงื่อนไขภายใน function เดียวกัน
export async function getProduct(id: string) {
"use cache"
const product = await db.product.findUnique({ where: { id } })
if (!product) {
// Short cache for missing items (may appear soon)
cacheLife("minutes")
return null
}
// Longer cache for existing products
cacheLife("product")
return product
}ตัวอย่างนี้แสดงการ cache ผลลัพธ์ null (สินค้าไม่พบ) ด้วยเวลาสั้น เนื่องจากสินค้าอาจถูกเพิ่มเข้ามาเร็ว ๆ นี้ แต่สินค้าที่มีอยู่จะใช้ custom profile ที่ cache นานกว่า
พร้อมที่จะพิชิตการสัมภาษณ์ React / Next.js แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
cacheTag สำหรับการ Invalidate เฉพาะจุด
ระบบ cacheTag ช่วยให้สามารถ invalidate cache ได้อย่างแม่นยำโดยไม่ต้อง invalidate ทุกอย่าง ทำงานร่วมกับ use cache next.js เพื่อสร้างระบบ cache ที่ยืดหยุ่น
import { cacheLife, cacheTag } from "next/cache"
export async function getProductById(id: string) {
"use cache"
cacheTag(`product-${id}`, "products")
cacheLife("days")
return db.product.findUnique({ where: { id } })
}ในตัวอย่างนี้ function ถูก tag ด้วยสอง tag: tag เฉพาะสินค้า (product-${id}) และ tag กลุ่มสินค้า (products) ทำให้สามารถ invalidate ได้ทั้งระดับสินค้าเดี่ยวและระดับทั้งหมวดหมู่
การใช้ revalidateTag ใน Server Actions
เมื่อมีการอัปเดตข้อมูล สามารถ invalidate cache ที่เกี่ยวข้องผ่าน revalidateTag ได้
"use server"
import { revalidateTag } from "next/cache"
export async function updateProduct(id: string, data: ProductUpdate) {
await db.product.update({ where: { id }, data })
// Invalidate this specific product AND the product list
revalidateTag(`product-${id}`)
revalidateTag("products")
}การ invalidate ทั้งสอง tag ทำให้:
- หน้าสินค้าเฉพาะ (
product-${id}) แสดงข้อมูลใหม่ - หน้ารายการสินค้าทั้งหมด (
products) แสดงข้อมูลที่อัปเดตแล้วเช่นกัน
cached function ที่ไม่มี cacheTag() จะหมดอายุได้ด้วยเวลาเท่านั้น ไม่สามารถ invalidate ตามต้องการได้ ปัญหานี้มักถูกมองข้ามในช่วงพัฒนาและพบเจอเมื่อข้อมูลเก่าปรากฏบน production แล้ว
ความปลอดภัย: use cache และ use cache private
ประเด็นที่สำคัญที่สุดของ cache components คือความปลอดภัยของข้อมูล การ cache ข้อมูลส่วนบุคคลด้วย "use cache" ธรรมดาจะทำให้ข้อมูลถูกแชร์ระหว่างผู้ใช้ทุกคน ซึ่งเป็นช่องโหว่ความปลอดภัยร้ายแรง
// WRONG: User data in shared cache - data leak risk
export async function getUserDashboard(userId: string) {
"use cache"
return db.user.findUnique({
where: { id: userId },
include: { orders: true, preferences: true },
})
}
// CORRECT: Private cache scoped to the current user
export async function getUserDashboard() {
"use cache: private"
cacheLife("minutes")
const session = await cookies()
const userId = session.get("userId")?.value
return db.user.findUnique({
where: { id: userId },
include: { orders: true, preferences: true },
})
}ความแตกต่างที่สำคัญ:
- ตัวอย่างแรกรับ
userIdเป็น parameter ซึ่งทำให้ cache ถูกแชร์ - ตัวอย่างที่ถูกต้องใช้
"use cache: private"และดึง userId จาก cookies ภายใน function
| Directive | ขอบเขต | ใช้เมื่อ |
|-----------|--------|--------|
| "use cache" | แชร์ร่วม ทุกผู้ใช้ | ข้อมูลสาธารณะ: ราคา, บทความ, แคตตาล็อกสินค้า |
| "use cache: private" | เฉพาะผู้ใช้แต่ละคน | ข้อมูลส่วนบุคคล: แดชบอร์ด, การตั้งค่า, ประวัติคำสั่งซื้อ |
| "use cache: remote" | แชร์ร่วม จัดเก็บภายนอก | ข้อมูลที่มีการเข้าถึงสูงในสภาพแวดล้อม serverless |
การ Migrate จาก Next.js 15 สู่ Cache Components
การ migrate จาก Next.js 15 ไปยังระบบ cache components ของ Next.js 16 ควรทำเป็นขั้นตอน:
-
เปิดใช้งาน cacheComponents - เพิ่ม
cacheComponents: trueในnext.config.ts -
ตรวจสอบ fetch ที่มี cache option - หา
fetch()ที่มีcache: 'force-cache'หรือrevalidateและแทนที่ด้วย"use cache"และcacheLife -
ระบุข้อมูลที่ต้อง cache - วิเคราะห์ว่าข้อมูลส่วนไหนควรถูก cache และใช้ directive ที่เหมาะสม
-
ตรวจสอบความปลอดภัย - ตรวจสอบว่าข้อมูลส่วนบุคคลทั้งหมดใช้
"use cache: private" -
กำหนด cacheTag - เพิ่ม tag ให้กับ cached function เพื่อรองรับ cache invalidation
-
ทดสอบอย่างละเอียด - ตรวจสอบว่าข้อมูลแสดงถูกต้องและ invalidation ทำงานตามที่คาดหวัง
เริ่มต้นจากหน้าที่เป็น static อย่างชัดเจน เช่น landing pages และหน้าเอกสาร จากนั้นค่อยเพิ่ม caching แบบ granular ให้กับ component แต่ละตัวในหน้าที่มีเนื้อหาผสมระหว่าง static และ dynamic
คำถามสัมภาษณ์ Next.js 16 Cache Components
หัวข้อนี้รวบรวม next.js 16 interview questions ที่พบบ่อยในการสัมภาษณ์นักพัฒนา:
คำถาม 1: อธิบายความแตกต่างระหว่างระบบ caching ของ Next.js 15 และ Next.js 16
Next.js 15 ใช้ implicit caching โดย cache ทุกอย่างโดยอัตโนมัติและต้อง opt-out ส่วน Next.js 16 ใช้ explicit caching โดยไม่ cache อะไรเลยและต้อง opt-in ด้วย "use cache" directive การเปลี่ยนแปลงนี้ทำให้พฤติกรรม caching ชัดเจนในโค้ด ลดปัญหาข้อมูลเก่าที่ไม่ตั้งใจ และเพิ่มความปลอดภัยโดยกำจัดการรั่วไหลของข้อมูล
คำถาม 2: สามระดับของ use cache directive คืออะไร และใช้งานเมื่อไหร่
ระดับไฟล์ใช้สำหรับหน้าที่เนื้อหาคงที่ทั้งหมด ระดับ component ใช้สำหรับ cache เฉพาะบาง component ในหน้าที่มีเนื้อหาผสม (pattern ของ PPR) ระดับ function ใช้สำหรับ data fetching function ที่ถูกเรียกจากหลายที่ การเลือกระดับกำหนด cache granularity และขอบเขตการ invalidation
คำถาม 3: Partial Pre-Rendering (PPR) คืออะไร และทำงานอย่างไร
PPR คือการแบ่งหน้าเป็น static shell ที่ส่งทันทีจาก CDN และ dynamic holes ที่ stream เข้ามาทีหลังผ่าน Suspense boundaries ช่วยให้ TTFB ต่ำมากแม้หน้ามีข้อมูล dynamic โดย component ที่มี "use cache" จะเป็นส่วนของ static shell และ component ที่อ่าน cookies หรือ headers จะ stream แบบ dynamic
คำถาม 4: ความแตกต่างระหว่าง use cache และ use cache private คืออะไร
"use cache" สร้าง shared cache ที่ผู้ใช้ทุกคนเข้าถึงได้ เหมาะสำหรับข้อมูลสาธารณะ ส่วน "use cache: private" สร้าง cache เฉพาะผู้ใช้แต่ละคนโดยรวม session ปัจจุบันใน cache key เหมาะสำหรับข้อมูลส่วนบุคคลที่ต้องไม่รั่วไหลไปยังผู้ใช้อื่น
คำถาม 5: cacheTag และ revalidateTag ทำงานร่วมกันอย่างไร
cacheTag() ใช้ติด tag ให้กับ cached entry ส่วน revalidateTag() ใช้ invalidate cache ที่มี tag ที่ระบุผ่าน Server Action ตัวอย่างเช่น สินค้าอาจมี tag product-123 และ products เมื่อสินค้าถูกอัปเดต การเรียก revalidateTag('product-123') จะ invalidate สินค้าเฉพาะ และ revalidateTag('products') จะ invalidate รายการสินค้าทั้งหมด
คำถาม 6: อธิบายความหมายของ stale, revalidate และ expire ใน cacheLife profile
stale คือระยะเวลาที่ยอมให้ serve ข้อมูลเก่าได้ revalidate คือความถี่ในการ revalidate เบื้องหลัง expire คือเวลาที่ cache หมดอายุอย่างถาวรและต้อง fetch ใหม่ ทั้งสามค่าทำงานร่วมกันเป็นระบบสามมิติที่แทนที่ค่า revalidate ตัวเลขเดียวของ Next.js 15
สำหรับการเตรียมตัวสัมภาษณ์เพิ่มเติม แนะนำให้ศึกษา:
Checklist สำหรับการใช้งาน Cache Components
รายการตรวจสอบสำหรับการนำ cache components ไปใช้งานจริง:
- กำหนด
cacheComponents: trueในnext.config.tsและลบ flagexperimental.pprหรือexperimental.dynamicIO - Audit ทุกหน้า: เพิ่ม
"use cache"ให้หน้า static และ data-fetching functions สำหรับข้อมูลสาธารณะ - ห่อ dynamic content ทั้งหมด (ข้อมูลเฉพาะผู้ใช้ request-time) ใน
<Suspense>boundaries พร้อม skeleton fallback ที่มีความหมาย - ใช้
"use cache: private"สำหรับ function ที่เข้าถึง cookies, headers หรือคืนค่าข้อมูลส่วนบุคคล - กำหนด custom
cacheLifeprofiles สำหรับหมวดหมู่ข้อมูลทั่วไป - เพิ่ม
cacheTag()ให้ทุก cached function ที่อาจต้อง invalidate ตามต้องการ - ทดสอบใน production mode ด้วย
next build && next startเนื่องจาก caching behavior ในnext devแตกต่างอย่างมาก - ติดตาม cache-hit ratio ต่อหน้าเป็นเวลา 24 ชั่วโมงก่อนเปิดใช้งานกับหน้าถัดไป
เริ่มฝึกซ้อมเลย!
ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ
สรุป
- Next.js 16 แทนที่ implicit caching ด้วย
"use cache"แบบชัดเจนในระดับไฟล์ component และ function - PPR เป็น stable แล้วและทำงานภายใต้
cacheComponents: trueส่ง static shells พร้อม stream dynamic content cacheLifeprofiles แทนที่revalidateด้วยการควบคุมระยะเวลา cache แบบสามมิติที่จัดการจากส่วนกลางcacheTag+revalidateTagช่วยให้ invalidate ตามต้องการได้ หาก function ไม่มี tag จะหมดอายุด้วยเวลาเท่านั้น"use cache: private"จำเป็นสำหรับข้อมูลเฉพาะผู้ใช้เพื่อป้องกันการรั่วไหลของข้อมูลระหว่างผู้ใช้- คำถามสัมภาษณ์ในปี 2026 เน้นที่การเปลี่ยนจาก implicit เป็น explicit, การทำงานของ PPR, ความปลอดภัยของ cache และข้อควรระวังในการ migrate จาก Next.js 15
แท็ก
แชร์
บทความที่เกี่ยวข้อง

React Compiler ในปี 2026: Automatic Memoization และคำถามสัมภาษณ์งาน
เรียนรู้ React Compiler ที่ทำ memoization อัตโนมัติ พร้อมคำถามสัมภาษณ์งานยอดนิยมสำหรับนักพัฒนา React ในปี 2026

React 19 useEffectEvent และ Activity: API ใหม่พร้อมคำถามสัมภาษณ์งาน 2026
เจาะลึก useEffectEvent และ Activity component ใน React 19.2 แก้ปัญหา stale closure, pre-rendering เบื้องหลัง พร้อมตัวอย่างโค้ดและคำถามสัมภาษณ์

React 19: Server Components ในระบบ Production - คู่มือฉบับสมบูรณ์
เชี่ยวชาญ React 19 Server Components ในระบบ Production สถาปัตยกรรม รูปแบบการออกแบบ Streaming Caching และการเพิ่มประสิทธิภาพสำหรับแอปพลิเคชันที่มีประสิทธิภาพสูง