Derived Stores — Svelte

Derived store otomatis menghitung nilai berdasarkan store lain. Membuat Derived Store import { derived } from "svelte/store" import { count } from…

Derived store adalah store yang nilainya dihitung dari store lain, dan dihitung ulang sendiri setiap sumbernya berubah. Bayangin layar kasir Warung Bu Sri yang tersambung ke keranjang. Setiap pelayan menambah pesanan, angka total di layar ikut berganti sendiri. Kasir gak bisa mengetik totalnya dengan tangan; kalau mau angkanya berubah, isi keranjangnya yang harus diubah. Di pelajaran Reactive Declarations, rumus seperti itu ditulis $: total = ... di dalam satu komponen. Derived store adalah rumus yang sama, tapi tinggal di stores.js dan dipakai banyak komponen.

🧪 Tebakan cepat: total adalah derived store dari keranjang. Kasir yang iseng menjalankan total.set(0) supaya pesanannya gratis. Totalnya jadi Rp 0, atau error? Jawabannya ada di bagian "Derived itu read-only".

derived: store dari store lain

Ini stores.js dari pelajaran Stores, ditambah total:

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

export const keranjang = writable([])

export const total = derived(keranjang, ($keranjang) =>
  $keranjang.reduce((jumlah, m) => jumlah + m.harga, 0)
)

Membaca derived store

Derived store dibaca persis seperti store lain, dengan $:

<!-- Kasir.svelte -->
<script>
  import { total } from "./stores.js"
</script>

<p>Total: Rp {$total.toLocaleString("id-ID")}</p>
Kejadian Isi keranjang total Kasir
Awal [] 0 Total: Rp 0
Tambah Nasi Goreng 1 item, 15000 15000 Total: Rp 15.000
Tambah Es Teh 2 item, 15000 + 5000 20000 Total: Rp 20.000

Gak ada satu baris pun yang menulis ke total. Tombol Tambah cuma memanggil keranjang.update(...), dan rumusnya dijalankan ulang sendiri.

Dari beberapa store sekaligus

Sumbernya boleh array. Rumusnya lalu menerima array isi, dengan urutan yang sama:

export const diskon = writable(0)

export const bayar = derived([total, diskon], ([$total, $diskon]) =>
  $total - ($total * $diskon) / 100
)

Dengan keranjang berisi Nasi Goreng (total 15000), ini yang dijalankan Svelte 4 yang sebenarnya:

Kejadian Rumus total Rumus bayar $bayar
Tambah Nasi Goreng jalan jalan 15000
diskon.set(10) gak jalan jalan 13500
diskon.set(10) lagi gak jalan gak jalan 13500

Derived itu read-only

Derived store cuma punya subscribe. Gak ada set, gak ada update. Jadi total.set(0) berakhir dengan:

TypeError: total.set is not a function

Totalnya tetap Rp 15.000, bukan Rp 0. Itu jawaban tebakannya. Nilai derived store selalu hasil rumus dari sumbernya; kalau mau totalnya berubah, ubah keranjang.

📌 Dihitung cuma kalau ada yang membaca

Derived store baru bekerja saat punya pelanggan. Rumusnya jalan sekali ketika pelanggan pertama datang (misalnya komponen yang menulis {$bayar} dibuat), lalu tiap sumbernya berubah. Derived store yang gak dibaca komponen mana pun gak pernah menjalankan rumusnya, berapa kali pun keranjangnya diubah. Jadi derived store yang mahal dihitung aman ditaruh di stores.js: dia cuma bekerja kalau dipakai.

Latihan: doubled

Latihannya memakai angka kecil. Kode awal sudah punya count = writable(5):

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

  const count = writable(5)
  const doubled = derived(count, ($c) => $c * 2)
</script>

<p>{$count} x 2 = {$doubled}</p>

Svelte 5

Derived store tetap jalan di Svelte 5. Untuk nilai turunan di dalam satu komponen, Svelte 5 memakai rune $derived: let total = $derived(keranjang.reduce((jumlah, m) => jumlah + m.harga, 0)), dengan keranjang dibuat dari $state. Derived store tetap pilihan yang pas untuk nilai turunan yang dipakai banyak komponen lewat stores.js.

⚠️ Jebakan yang sering ketemu

TL;DR: derived(sumber, rumus) dari "svelte/store" membuat store yang nilainya dihitung dari store lain, misalnya total = derived(keranjang, ($keranjang) => ...jumlah harga). Rumusnya jalan ulang sendiri tiap sumbernya berubah, dan dibaca dengan {$total} seperti store lain. Sumbernya bisa array: derived([total, diskon], ([$total, $diskon]) => ...), dan diskon baru cuma menjalankan ulang rumus bayar. Derived store read-only: total.set(0) menghasilkan TypeError: total.set is not a function, jadi jawabannya "tidak bisa di-set". Rumusnya cuma jalan kalau ada pelanggan. Latihannya: const doubled = derived(count, ($c) => $c * 2) dan <p>{$count} x 2 = {$doubled}</p>, yang menampilkan 5 x 2 = 10.

Yang akan kamu pelajari