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

The $effect Rune

$effect รัน function หลัง DOM update แล้ว และรันซ้ำทุกครั้งที่ค่า reactive ที่อ่านเปลี่ยน มีไว้สำหรับ side effect — sync state ของ Svelte กับสิ่งที่อยู่นอก Svelte: DOM ตรง ๆ, library ภายนอก, subscription, timer, logging, localStorage

<script>
let count = $state(0);
$effect(() => {
// Runs after render, and again whenever count changes.
document.title = `Count: ${count}`;
});
</script>

dependency ถูก track อัตโนมัติ เหมือน $derived เป๊ะ — effect อ่าน count จึงรันซ้ำเมื่อ count เปลี่ยน ไม่ต้องมี dependency array

ถ้า effect ตั้งอะไรบางอย่างที่ต้อง tear down — interval, event listener, subscription — ให้ return cleanup function Svelte จะรัน cleanup ก่อน effect รันซ้ำ และตอน component ถูก destroy

<script>
let seconds = $state(0);
$effect(() => {
const id = setInterval(() => seconds++, 1000);
return () => clearInterval(id); // cleanup: runs before re-run and on destroy
});
</script>

$effect รัน หลัง DOM update บางครั้งคุณต้องอ่าน DOM ก่อน DOM update — เช่น จับ scroll position ก่อน content ใหม่จะดันตำแหน่งไป $effect.pre รันก่อน DOM update แทน โดยมีกฎ track และ cleanup เหมือนกัน

<script>
let messages = $state([]);
$effect.pre(() => {
messages.length; // track the dependency
// read scroll position BEFORE the DOM updates with new messages
});
</script>

นี่คือแนวทางที่สำคัญที่สุดในโมดูล effect คือ escape hatch และการหยิบมาจัดการ state ภายใน คือความผิดพลาดที่พบบ่อยที่สุดใน Svelte 5 ก่อนเขียน effect ให้ถามว่า:

  • คำนวณค่าจาก state? ใช้ $derived ไม่ใช่ effect ที่ assign state
  • ตอบสนอง user action? ทำงานใน event handler (onclick) ไม่ใช่ effect ที่คอยดูตัวแปร
  • mirror prop ลง state? มักเป็น design smell — derive จาก prop แทน
flowchart TB
  q["ต้อง react ต่อ state?"] --> derive["คำนวณค่า? ใช้ $derived"]
  q --> handler["จาก user action? ใช้ event handler"]
  q --> effect["sync กับสิ่งนอก Svelte? ใช้ $effect"]
เลือกเครื่องมือให้ถูก

effect เป็นเครื่องมือที่ถูกก็ต่อเมื่อคุณเชื่อมไปยังสิ่งที่ Svelte ไม่ได้ควบคุม — document title, canvas, websocket, localStorage, analytics call ถ้างานยังอยู่ในโลก reactive ของ Svelte rune อย่าง $derived มักเหมาะกว่าเสมอ

`$effect` มีไว้ทำอะไร?
จะ tear down subscription หรือ interval ที่สร้างใน effect ยังไง?
คุณอยากคำนวณ `fullName` จาก `first` กับ `last` ควรใช้อะไร?
ความต่างระหว่าง `$effect` กับ `$effect.pre` คืออะไร?