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

The Store Contract

Svelte store ไม่มีอะไร magic เลย store คือ object ใด ๆ ที่มี method subscribe ที่รับ callback แล้วเรียก callback นั้นด้วยค่าปัจจุบัน ทั้งทันทีและทุกครั้งที่ค่าเปลี่ยน — โดย return ฟังก์ชัน unsubscribe กลับมา นั่นคือ contract ทั้งหมด:

// The minimal store contract, written by hand.
function createCounter() {
let value = 0;
const subscribers = new Set();
return {
subscribe(fn) {
fn(value); // 1. call immediately with the current value
subscribers.add(fn);
return () => subscribers.delete(fn); // 2. return an unsubscribe function
},
increment() {
value += 1;
subscribers.forEach((fn) => fn(value)); // 3. notify on change
},
};
}

เพราะ contract เล็กขนาดนี้ อะไรก็ตาม ที่ทำตาม contract นี้ได้ก็เป็น store — รวมถึง RxJS observable (ที่ก็มี subscribe ที่เข้ากันได้) ความ interoperable นี้คือเหตุผลที่ Svelte นิยาม contract ไว้แทนที่จะเป็น class ตายตัว

การเขียน store.subscribe(...) เองในทุกคอมโพเนนต์คงน่าเบื่อและ leak ง่าย ในคอมโพเนนต์ Svelte ให้ shorthand $store: เติม $ หน้า store แล้ว Svelte จะ subscribe ให้ ให้ค่าปัจจุบัน re-render เมื่อค่าเปลี่ยน และ unsubscribe ให้อัตโนมัติ เมื่อคอมโพเนนต์ถูกทำลาย

<script>
import { counter } from './counter.js';
</script>
<!-- $counter is the current value; the component re-renders on every change -->
<button onclick={counter.increment}>count is {$counter}</button>
flowchart LR
  prefix["$store ในคอมโพเนนต์"] --> sub["subscribe ตอน mount"]
  sub --> val["อ่านค่าปัจจุบัน"]
  val --> rerender["re-render เมื่อค่าเปลี่ยน"]
  rerender --> unsub["auto-unsubscribe ตอน destroy"]
prefix $ ทำอะไรให้บ้าง

คุณยัง assign ให้ $store ได้ด้วย ($counter = 5) ถ้า store เป็น writable — Svelte จะ compile เป็นการเรียก set ของ store prefix $ ใช้ได้เฉพาะในไฟล์ .svelte และ module .svelte.js/.svelte.ts เพราะเป็น compiler magic ไม่ใช่ฟังก์ชัน runtime

ถึงแม้ runes จะครอบคลุม shared-state ส่วนใหญ่แล้ว (บทถัด ๆ ไป) store contract ก็ยังมีค่า:

  • interop source ใด ๆ ที่คล้าย observable และมี subscribe ที่เข้ากันได้ก็ใช้กับ $ ได้ — RxJS, custom event stream, third-party library
  • async source readable (บทถัดไป) ห่อ source แบบ push (WebSocket, geolocation watcher) ไว้หลัง contract ง่าย ๆ อันเดียวกัน
  • code เดิม Svelte หลายล้านบรรทัดใช้ stores การเข้าใจ contract ช่วยให้คุณอ่านและดูแล code เหล่านั้นได้
อะไรทำให้บางอย่างเป็น Svelte store?
prefix `$store` ทำอะไรในคอมโพเนนต์?
ทำไม RxJS observable ถึงใช้กับ syntax `$` ของ Svelte ได้?
prefix `$store` ใช้ได้ที่ไหน?