Mutations และ Revalidation
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”mutation คือ flow สี่ขั้น validate input, เขียนลง database, เรียก revalidateTag หรือ revalidatePath เพื่อ refresh ข้อมูลที่ cache ไว้ซึ่งได้รับผลกระทบ และ redirect ถ้าจำเป็น เพื่อให้ UI สะท้อนการเปลี่ยนแปลงโดยไม่ต้อง reload เอง
The full mutation flow
หัวข้อที่มีชื่อว่า “The full mutation flow”ภายใน action เรา validate ก่อน แล้วค่อย mutate แล้วค่อย revalidate ข้อมูลที่เพิ่งเปลี่ยน หลัง revalidate แล้วจึง redirect เพราะ redirect throw ภายในและหยุดโค้ดที่เหลือของ function ไม่ให้รันต่อ
// app/actions.ts — validate, write, revalidate, redirect'use server'
import { revalidatePath } from 'next/cache'import { redirect } from 'next/navigation'import { z } from 'zod'
const schema = z.object({ title: z.string().min(1) })
export async function createPost(formData: FormData) { const parsed = schema.safeParse({ title: formData.get('title') }) if (!parsed.success) { return { error: 'Invalid title' } }
await db.post.create({ data: { title: parsed.data.title } })
revalidatePath('/posts') redirect('/posts')}revalidateTag vs revalidatePath
หัวข้อที่มีชื่อว่า “revalidateTag vs revalidatePath”revalidatePath('/posts') invalidate ทุกอย่างที่ cache ไว้สำหรับ route นั้น ส่วน revalidateTag('posts') invalidate เฉพาะ fetch ที่เรา tag ด้วย 'posts' จึงตรงจุดกว่าเมื่อข้อมูลเดียวกันโผล่ในหลาย route ให้ tag ตอน read แล้ว invalidate ด้วย tag หลัง write
// app/posts/data.ts — tag the read so you can revalidate by tag laterexport async function getPosts() { const res = await fetch('https://api.example.com/posts', { next: { tags: ['posts'] }, }) return res.json()}// app/actions.ts — invalidate only the tagged data'use server'
import { revalidateTag } from 'next/cache'
export async function publishPost(id: string) { await db.post.update({ where: { id }, data: { published: true } }) revalidateTag('posts')}How the client caches get refreshed
หัวข้อที่มีชื่อว่า “How the client caches get refreshed”ส่วนนี้โยงกลับไปที่ caching module ฝั่ง server การ revalidate จะล้าง entry ใน Data Cache ของ fetch ที่ได้รับผลกระทบ ฝั่ง client response ของ Server Action ยัง refresh Router Cache ของ route ปัจจุบันด้วย segment ที่ render ไปแล้วจึงถูกแทนด้วย output ใหม่จาก server ผู้ใช้เห็นข้อมูลใหม่โดยไม่ต้อง hard reload cache ทั้งสองตัวจึงคงความ consistent
graph TD A["Action validates input"] --> B["Writes to the database"] B --> C["revalidateTag or revalidatePath"] C --> D["Data Cache entry cleared"] C --> E["Router Cache refreshed"] D --> F["UI shows fresh data"] E --> F B --> G["Optional redirect after revalidate"]