Cross-Component State
แพทเทิร์น 1: shared module
หัวข้อที่มีชื่อว่า “แพทเทิร์น 1: shared module”cross-component state ที่ง่ายที่สุดคือค่า reactive ที่ export จาก .svelte.js module ทุกคนที่ import จะ share instance เดียว:
export const theme = $state({ mode: 'light' });
export function toggle() { theme.mode = theme.mode === 'light' ? 'dark' : 'light';}คอมโพเนนต์ใด ๆ import theme และ toggle แล้วจะ sync กัน เหมาะกับ state ที่ global จริง ๆ และมี instance เดียว: color theme, toast queue, feature-flag set
กับดัก SSR singleton
หัวข้อที่มีชื่อว่า “กับดัก SSR singleton”มีข้อควรระวังที่สำคัญทันทีที่คุณใช้ SvelteKit (หรือ SSR ใด ๆ) module-level $state คือ instance เดียวที่ทุกคนที่ import แชร์กัน — รวมถึงบน server ที่ ทุก request ที่ถูกจัดการโดย process เดียวกัน เอา logged-in user ไปไว้ใน module-level singleton แล้วภายใต้ SSR request หนึ่งอาจเห็นข้อมูลของ user อีกคนได้
แพทเทิร์น 2: per-subtree instance ด้วย context
หัวข้อที่มีชื่อว่า “แพทเทิร์น 2: per-subtree instance ด้วย context”เมื่อคุณต้องการ state ที่ share ภายใน subtree แต่ แยกกันต่อ instance — และปลอดภัยภายใต้ SSR — ให้ผสม runed class/object กับ setContext / getContext parent สร้าง state แล้วเอาไปไว้ใน context ส่วน descendant อ่านค่าไปใช้ แต่ละ instance ของคอมโพเนนต์ได้ของตัวเอง สร้างตอน render ของ request นั้น
<script> import { setContext } from 'svelte';
// created fresh per instance / per request — not a module singleton const cart = $state({ items: [] }); setContext('cart', cart);</script>
<slot /><script> import { getContext } from 'svelte'; const cart = getContext('cart'); // the same reactive object the parent set</script>
<button onclick={() => cart.items.push(item)}>add ({cart.items.length})</button>เพราะ state ถูกสร้างภายใน component tree (ไม่ใช่ตอน module load) แต่ละ render — และแต่ละ SSR request — ได้ copy ของตัวเอง idiom ที่พบบ่อยคือ factory เล็ก ๆ (createCart()) ที่ return runed state เรียกใน parent แล้ว share ผ่าน context
flowchart TB local["แค่คอมโพเนนต์เดียว: local state"] --> up["ไม่กี่คอมโพเนนต์ที่เกี่ยวกัน: lift state ไป parent แล้วส่ง props"] up --> ctx["subtree แบบ per-instance หรือ per-user: setContext + runed state"] ctx --> mod["global จริง ๆ instance เดียว: export state จาก .svelte.js module"] mod --> store["ต้องการ subscribe contract: ใช้ store"]
decision guide
หัวข้อที่มีชื่อว่า “decision guide”- Local —
$stateในคอมโพเนนต์ เริ่มที่นี่ - Lift — ย้าย
$stateไปที่ parent ร่วมที่ใกล้ที่สุด ส่งลงเป็น props สำหรับคอมโพเนนต์ที่เกี่ยวกันไม่กี่ตัว - Context —
setContext/getContextกับ runed state สำหรับ subtree ที่ต้องการ instance ของตัวเอง (และความปลอดภัยแบบ SSR) - Module — export
$stateจาก.svelte.jsmodule สำหรับ state ที่ global จริง ๆ instance เดียว - Store — เมื่อต้องการ subscribe contract (interop, external push source)
ให้เลือกระดับ ต่ำที่สุด ที่แก้ปัญหาได้ แล้วค่อยเลื่อนขึ้นเมื่อจำเป็นเท่านั้น