ข้ามไปยังเนื้อหา

Mutations และ Revalidation

mutation คือ flow สี่ขั้น validate input, เขียนลง database, เรียก revalidateTag หรือ revalidatePath เพื่อ refresh ข้อมูลที่ cache ไว้ซึ่งได้รับผลกระทบ และ redirect ถ้าจำเป็น เพื่อให้ UI สะท้อนการเปลี่ยนแปลงโดยไม่ต้อง reload เอง

ภายใน 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')
}

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 later
export 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')
}

ส่วนนี้โยงกลับไปที่ 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"]
The mutation and revalidation flow
What is the correct order of the mutation flow?
Why must redirect come after revalidation in an action?
When is revalidateTag more useful than revalidatePath?
Which client-side cache does the action response refresh?