$effect — Side Effects
useEffect มี footgun ที่เป็นที่รู้จักดี: ลืมตัวแปรใน dependency array และ effect ของคุณจะรันด้วยค่าเก่า ใส่มากเกินไปและจะรันบ่อยเกินไป $effect ของ Svelte 5 แก้ปัญหานี้โดยสิ้นเชิง — ไม่มี dependency array effect รันครั้งแรก จากนั้นรันใหม่อัตโนมัติทุกครั้งที่ reactive value ที่อ่านในการรันก่อนหน้าเปลี่ยน คอมไพเลอร์ track dependencies แทนคุณ
Side effect พื้นฐาน
หัวข้อที่มีชื่อว่า “Side effect พื้นฐาน”function TitleSync() { const [count, setCount] = React.useState(0);
React.useEffect(() => { document.title = 'Count: ' + count; }, [count]); // <-- must list count here
return <button onClick={() => setCount(c => c + 1)}>+1 (count: {count})</button>;}<script> let count = $state(0);
$effect(() => { document.title = 'Count: ' + count; // count ถูกอ่านที่นี่ จึงถูก track อัตโนมัติ });</script>
<button onclick={() => count++}>+1 (count: {count})</button>ไม่มี [count] effect อ่าน count ดังนั้น Svelte รู้ว่าต้องรันใหม่เมื่อ count เปลี่ยน
$effect รันเมื่อไหร่?
หัวข้อที่มีชื่อว่า “$effect รันเมื่อไหร่?”- การรันแรก: หลัง component mount (เหมือน
useEffectที่ไม่มี deps) - รันใหม่: synchronously หลัง reactive dependency ที่อ่านในการรันก่อนหน้าเปลี่ยน
- ไม่รันระหว่าง render: ต่างจาก
useMemo,$effectไม่รันในขั้นตอน rendering แบบ synchronous
Cleanup
หัวข้อที่มีชื่อว่า “Cleanup”Return function จาก $effect เพื่อ cleanup ก่อนการรันครั้งถัดไปหรือเมื่อ component ถูกทำลาย — เหมือนรูปแบบ cleanup ของ useEffect ทุกประการ
function Timer() { const [seconds, setSeconds] = React.useState(0);
React.useEffect(() => { const id = setInterval(() => setSeconds(s => s + 1), 1000); return () => clearInterval(id); // cleanup }, []);
return <p>Elapsed: {seconds}s</p>;}<script> import { onMount } from 'svelte'; let seconds = $state(0);
onMount(() => { const id = setInterval(() => seconds++, 1000); return () => clearInterval(id); // cleanup });</script>
<p>Elapsed: {seconds}s</p>สำหรับรูปแบบ “รันครั้งเดียวเมื่อ mount + cleanup เมื่อ destroy”, onMount ใช้งานง่ายกว่า $effect ดูเพิ่มเติมในบทเรียน Lifecycle
$effect สำหรับ localStorage sync
หัวข้อที่มีชื่อว่า “$effect สำหรับ localStorage sync”กรณีการใช้งาน useEffect ที่พบบ่อย — sync state กับ localStorage — map ตรงกัน:
function ThemeToggle() { const [theme, setTheme] = React.useState( () => localStorage.getItem('theme') ?? 'light' );
React.useEffect(() => { localStorage.setItem('theme', theme); document.body.setAttribute('data-theme', theme); }, [theme]);
return ( <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}> Theme: {theme} </button> );}<script> let theme = $state( typeof localStorage !== 'undefined' ? (localStorage.getItem('theme') ?? 'light') : 'light' );
$effect(() => { localStorage.setItem('theme', theme); document.body.setAttribute('data-theme', theme); });</script>
<button onclick={() => theme = theme === 'light' ? 'dark' : 'light'}> Theme: {theme}</button>