Stores Svelte — Svelte

Stores adalah cara mengelola state yang bisa diakses dari mana saja — state management bawaan Svelte. Writable Store // stores.js import { writable } from…

Store adalah wadah nilai yang hidup di luar komponen. Banyak komponen bisa membacanya dan mengubahnya, dan setiap komponen yang berlangganan (subscribe) dikabari tiap isinya berubah. Bayangin grup WhatsApp "Keranjang Warung Bu Sri". Pelayan menulis pesanan baru di grup, dan kasir serta koki langsung dapat notifikasinya, walaupun mereka gak saling menelepon. Anggota yang pulang keluar dari grup, supaya HP-nya gak terus berbunyi. Store bekerja persis begitu: menulis ke store adalah kirim pesan, subscribe adalah masuk grup, dan unsubscribe adalah keluar grup.

🧪 Tebakan cepat: Header.svelte mengimpor store keranjang lalu menulis <p>Keranjang: {keranjang}</p>, tanpa tanda $. Yang tampil Keranjang: [], Keranjang: [object Object], atau error? Jawabannya ada di bagian "Tanda $: berlangganan otomatis".

Kenapa butuh store

Di Warung Bu Sri, DaftarMenu.svelte punya tombol Tambah, dan Header.svelte menampilkan jumlah isi keranjang. Keduanya anak dari App, jadi gak bisa saling kirim props. Kamu bisa menaruh keranjang di App lalu mengopernya ke dua anak, tapi makin banyak komponen yang butuh, makin panjang operannya. Store menaruh nilainya di file sendiri, dan komponen mana pun tinggal mengimpornya.

writable: membuat store

// stores.js
import { writable } from "svelte/store"

export const keranjang = writable([])
Method Gunanya
subscribe(fn) memanggil fn sekarang dengan nilai saat ini, lalu tiap nilainya berubah. Mengembalikan function untuk berhenti berlangganan.
set(nilai) mengganti nilainya dengan nilai baru
update(fn) menghitung nilai baru dari nilai lama: update((k) => [...k, "Es Teh"])

Tanda $: berlangganan otomatis

Di file .svelte, tulis $ di depan nama store untuk membaca nilainya:

<!-- DaftarMenu.svelte -->
<script>
  import { keranjang } from "./stores.js"
  const menu = ["Nasi Goreng", "Mie Ayam", "Es Teh"]
</script>

{#each menu as nama}
  <button on:click={() => keranjang.update((k) => [...k, nama])}>Tambah {nama}</button>
{/each}
<button on:click={() => keranjang.set([])}>Kosongkan</button>
<!-- Header.svelte -->
<script>
  import { keranjang } from "./stores.js"
</script>

<p>Keranjang: {$keranjang.length} item</p>
Kejadian Isi keranjang Header
Awal [] Keranjang: 0 item
Klik Tambah Nasi Goreng ["Nasi Goreng"] Keranjang: 1 item
Klik Tambah Es Teh ["Nasi Goreng", "Es Teh"] Keranjang: 2 item
Klik Kosongkan [] Keranjang: 0 item

subscribe manual dan unsubscribe

Kadang kamu butuh nilainya di dalam <script>, atau di file .js. Panggil subscribe sendiri, dan simpan function yang dikembalikannya:

<script>
  import { onDestroy } from "svelte"
  import { keranjang } from "./stores.js"

  let isi = []
  const unsubscribe = keranjang.subscribe((k) => {
    isi = k
  })
  onDestroy(unsubscribe)
</script>

<p>Keranjang: {isi.length} item</p>

Kalau onDestroy(unsubscribe) dilupakan, Header yang sudah dilepas tetap terdaftar sebagai pelanggan, dan callback-nya terus dipanggil tiap keranjang berubah. Pasang dan lepas Header tiga kali, dan store punya tiga pelanggan, dua di antaranya komponen yang sudah gak ada. Ini kebocoran yang sama dengan interval di pelajaran Lifecycle. $keranjang gak punya masalah ini.

readable: store yang cuma bisa dibaca

readable(nilaiAwal, mulai) membuat store tanpa set dan update dari luar. Nilainya cuma diubah oleh function mulai di dalamnya:

import { readable } from "svelte/store"

export const jam = readable(new Date().toLocaleTimeString("id-ID"), (set) => {
  const timer = setInterval(() => set(new Date().toLocaleTimeString("id-ID")), 1000)
  return () => clearInterval(timer)
})

Latihan: count dan name

Latihan pertama, penghitung dengan store:

<script>
  import { writable } from "svelte/store"

  const count = writable(0)
</script>

<p>Count: {$count}</p>
<button on:click={() => $count += 1}>+1</button>

Awalnya Count: 0, satu klik jadi Count: 1, dua klik jadi Count: 2. Latihan kedua, sapaan yang ikut kolom isian:

<script>
  import { writable } from "svelte/store"

  const name = writable("Dunia")
</script>

<input bind:value={$name} />
<h1>Halo, {$name}!</h1>

Awalnya Halo, Dunia!. Ketik Sinta, dan judulnya jadi Halo, Sinta!.

Svelte 5

Store tetap jalan di Svelte 5, termasuk $keranjang di komponen runes. Svelte 5 juga punya cara lain untuk state bersama: $state di file .svelte.js, misalnya export const keranjang = $state([]), lalu komponen mana pun memanggil keranjang.push("Es Teh"). Untuk jalur ini, store dari svelte/store sudah cukup dan masih banyak dipakai.

⚠️ Jebakan yang sering ketemu

TL;DR: Store adalah nilai di file sendiri yang bisa dibaca dan diubah banyak komponen. writable([]) dari "svelte/store" memberi subscribe, set, dan update. Di file .svelte, {$keranjang} berlangganan saat komponen dibuat dan berhenti saat dilepas; tanpa $, yang tampil [object Object]. $count += 1 dan bind:value={$name} menulis ke store. subscribe manual harus dipasangkan dengan unsubscribe di onDestroy, kalau gak, komponen yang sudah dilepas terus dikabari. readable gak bisa diubah dari luar; nilainya diatur function di dalamnya. Latihannya: const count = writable(0) dengan <p>Count: {$count}</p> dan tombol +1 yang membuatnya Count: 1 lalu Count: 2, dan const name = writable("Dunia") dengan <input bind:value={$name} /> dan <h1>Halo, {$name}!</h1>.

Yang akan kamu pelajari