เกิดอะไรขึ้น
หลังผู้ใช้ส่งฟอร์ม ข้อมูลบน server อัปเดตแล้ว แต่ถ้าผู้ใช้กลับไปหน้า list จะยังเห็นเนื้อหาเก่าอยู่นานถึง 30 วินาที พอ reload แบบ hard ข้อมูลกลับสดตามปกติ เลยทำให้ทำซ้ำเพื่อหาสาเหตุได้ยาก
ทำไมถึงเป็นแบบนั้น
revalidatePath ล้าง cache ฝั่ง server ของ path นั้น คือ Data Cache และ Full Route Cache แต่ browser ยังมี Router Cache ฝั่ง client ที่เก็บ RSC payload ของหน้าที่เคยเข้าไว้ใน memory ของ browser เอง server จึงสั่งล้างตรง ๆ ไม่ได้ ใน Next.js 14 หน้า dynamic จะอยู่ใน cache นี้ 30 วินาที
มีเงื่อนไขสำคัญคือ ถ้าเรียก revalidatePath ภายใน Server Action Next.js จะ invalidate Router Cache ฝั่ง client ให้ด้วย แต่ถ้า mutation ผ่าน Route Handler หรือ API ภายนอก จะไม่เกิดแบบนั้น และหน้าที่เคยเข้าอาจยังเป็นข้อมูลเก่า ใน Next.js 15 หน้าจะไม่ถูกใช้ซ้ำจาก Router Cache เป็นค่าเริ่มต้น (staleTimes เป็น 0) ปัญหานี้จึงพบน้อยลง แต่การกดย้อนกลับหรือไปข้างหน้าอาจยังเห็นหน้าที่เก็บไว้
ตอนนี้เราทำอย่างไร
ถ้า mutation ไม่ได้ผ่าน Server Action ให้เรียก router.refresh() จาก useRouter ฝั่ง client หลัง request สำเร็จ มันจะ refresh route ปัจจุบันและดึงข้อมูลใหม่ หรือจะย้าย mutation ไปเป็น Server Action แล้วเรียก revalidatePath ในนั้นก็ได้
เวลาทดสอบให้ลองส่งฟอร์ม กดลิงก์ไปหน้าอื่น แล้วกลับมาดูหน้า list เพราะการ reload จะซ่อนปัญหานี้ไว้
'use client'
import { useRouter } from 'next/navigation'
export function PostForm() {
const router = useRouter()
async function onSubmit(formData: FormData) {
const res = await fetch('/api/posts', { method: 'POST', body: formData })
if (res.ok) router.refresh()
}
return <form action={onSubmit}>{/* fields */}</form>
}เช็กลิสต์สั้น ๆ
- 1เช็กว่า mutation ผ่าน Server Action หรือ Route Handler
- 2ถ้าเป็น Route Handler ให้เรียก router.refresh() หลัง request สำเร็จ
- 3ถ้าเป็น Server Action ให้เรียก revalidatePath ในนั้น
- 4ทดสอบโดยคลิกเปลี่ยนหน้าไปมา ไม่ใช่แค่ reload
จำไว้สั้น ๆ
หลัง mutation ที่ไม่ผ่าน Server Action อย่าพึ่ง revalidatePath อย่างเดียว ให้ refresh router ฝั่ง client ด้วย และทดสอบด้วยการคลิกจริง