Dalam aplikasi SvelteKit, kita sering membutuhkan state yang dipakai di lebih dari satu komponen. Contoh paling umum adalah jumlah item keranjang, tema gelap/terang, atau kata kunci pencarian yang dipakai beberapa bagian antarmuka. Untuk kebutuhan seperti ini, store adalah solusi dasar yang sederhana dan praktis.
Pada tutorial ini, kita akan fokus pada dua jenis store yang paling sering dipakai pemula: writable dan derived. Kita tidak akan membahas teori reaktivitas terlalu panjang. Fokusnya adalah cara pakai di project SvelteKit, pola penempatan file, cara subscribe di komponen atau halaman, dan cara update state dengan pola yang umum dipakai.
Semua contoh di sini memakai struktur file terpisah di src/lib/stores agar kode lebih rapi dan mudah dipakai ulang.
Kapan Menggunakan Store di SvelteKit?
Store cocok dipakai ketika state:
- dibutuhkan oleh beberapa komponen berbeda,
- perlu tetap sinkron di banyak tempat,
- lebih nyaman disimpan di luar komponen daripada di
<script>lokal.
Kalau state hanya dipakai di satu komponen kecil, state lokal biasa sering sudah cukup. Jangan buru-buru memindahkan semua state ke store karena bisa membuat struktur menjadi berlebihan. Gunakan store saat memang ada kebutuhan berbagi state.
Membuat Store Writable Dasar
Writable store adalah store yang nilainya bisa dibaca dan diubah. Ini tipe store paling umum untuk counter, tema, form state sederhana, atau data UI lain yang berubah dari interaksi pengguna.
Struktur Folder
Buat folder store terpisah:
src/
lib/
stores/
cart.js
theme.js
search.jsPemisahan seperti ini membantu agar logika state tidak bercampur langsung dengan file halaman atau komponen.
Contoh 1: Cart Counter
Buat file src/lib/stores/cart.js:
import { writable } from 'svelte/store';
export const cartCount = writable(0);Store di atas menyimpan angka jumlah item di keranjang, dengan nilai awal 0.
Sekarang gunakan di komponen, misalnya src/routes/+page.svelte:
<script>
import { cartCount } from '$lib/stores/cart';
</script>
<h2>Demo Cart Counter</h2>
<p>Jumlah item di keranjang: {$cartCount}</p>
<button on:click={() => cartCount.update(n => n + 1)}>
Tambah Item
</button>
<button on:click={() => cartCount.update(n => Math.max(0, n - 1))}>
Kurangi Item
</button>
<button on:click={() => cartCount.set(0)}>
Reset
</button>Di Svelte, store bisa dipakai langsung di template dengan prefix $, misalnya $cartCount. Ini adalah cara subscribe paling praktis di file .svelte.
Ada tiga operasi dasar yang penting:
set(value): mengganti nilai langsung,update(fn): mengubah nilai berdasarkan nilai sebelumnya,subscribe(fn): membaca perubahan store secara manual.
Untuk kasus counter, update lebih aman daripada set karena kita menghitung nilai baru dari state sebelumnya.
Membungkus Logika Update agar Lebih Rapi
Untuk project yang mulai membesar, Anda bisa menyimpan aksi update di file store supaya komponen lebih bersih.
import { writable } from 'svelte/store';
function createCartCount() {
const { subscribe, set, update } = writable(0);
return {
subscribe,
increment: () => update(n => n + 1),
decrement: () => update(n => Math.max(0, n - 1)),
reset: () => set(0)
};
}
export const cartCount = createCartCount();Pemakaiannya di komponen:
<script>
import { cartCount } from '$lib/stores/cart';
</script>
<p>Jumlah item: {$cartCount}</p>
<button on:click={cartCount.increment}>Tambah</button>
<button on:click={cartCount.decrement}>Kurangi</button>
<button on:click={cartCount.reset}>Reset</button>Pola ini bagus untuk pemula karena logika perubahan state terkumpul di satu tempat dan komponen menjadi lebih mudah dibaca.
Contoh Store Writable untuk Tema
Kasus lain yang sangat umum adalah tema aplikasi, misalnya light dan dark.
Buat file src/lib/stores/theme.js:
import { writable } from 'svelte/store';
export const theme = writable('light');Lalu pakai di layout agar bisa dipakai banyak halaman, misalnya di src/routes/+layout.svelte:
<script>
import { theme } from '$lib/stores/theme';
</script>
<svelte:head>
<title>Demo Theme Store</title>
</svelte:head>
<div class={$theme}>
<button on:click={() => theme.set($theme === 'light' ? 'dark' : 'light')}>
Ganti ke {$theme === 'light' ? 'dark' : 'light'} mode
</button>
<slot />
</div>Anda bisa memberi styling berdasarkan class:
.light {
background: white;
color: black;
}
.dark {
background: #111;
color: white;
}Contoh ini sederhana, tetapi cukup untuk memahami bahwa satu store bisa dipakai lintas halaman dan lintas komponen.
Catatan: jika store tema bergantung pada
localStorageatau API browser lain, hati-hati dengan SSR. Kode yang menyentuh browser sebaiknya dijalankan di sisi klien, misalnya dionMount.
Menggunakan Derived Store
Derived store dipakai ketika nilai store lain perlu dihitung dari satu atau beberapa store sumber. Ini berguna agar kita tidak menyimpan data turunan secara manual.
Aturan praktisnya: jika sebuah nilai bisa dihitung dari state lain, sering kali lebih baik dijadikan derived store daripada store terpisah yang harus diupdate manual. Dengan begitu, risiko data tidak sinkron menjadi lebih kecil.
Contoh 2: Status Cart dari Cart Counter
Kita buat store turunan yang memberi label berdasarkan jumlah item di keranjang.
Perbarui file src/lib/stores/cart.js:
import { writable, derived } from 'svelte/store';
export const cartCount = writable(0);
export const cartLabel = derived(cartCount, ($cartCount) => {
return $cartCount === 0 ? 'Keranjang kosong' : `Total item: ${$cartCount}`;
});Pakai di komponen:
<script>
import { cartCount, cartLabel } from '$lib/stores/cart';
</script>
<p>{$cartLabel}</p>
<button on:click={() => cartCount.update(n => n + 1)}>Tambah</button>Keuntungan pendekatan ini adalah cartLabel akan selalu ikut berubah ketika cartCount berubah, tanpa perlu dipanggil manual.
Contoh 3: Filter Pencarian dengan Derived
Sekarang kita buat contoh yang lebih realistis: daftar produk sederhana dengan kata kunci pencarian. Kita akan memakai:
writableuntuk kata kunci,writableuntuk daftar data,deriveduntuk hasil filter.
Buat file src/lib/stores/search.js:
import { writable, derived } from 'svelte/store';
export const keyword = writable('');
export const products = writable([
{ id: 1, name: 'Keyboard Mechanical' },
{ id: 2, name: 'Mouse Wireless' },
{ id: 3, name: 'Monitor 24 Inch' },
{ id: 4, name: 'Laptop Stand' }
]);
export const filteredProducts = derived(
[keyword, products],
([$keyword, $products]) => {
const q = $keyword.trim().toLowerCase();
if (!q) return $products;
return $products.filter((product) =>
product.name.toLowerCase().includes(q)
);
}
);Lalu gunakan di halaman:
<script>
import {
keyword,
filteredProducts
} from '$lib/stores/search';
</script>
<h2>Filter Produk</h2>
<input
type="text"
placeholder="Cari produk..."
bind:value={$keyword}
/>
<ul>
{#each $filteredProducts as product}
<li>{product.name}</li>
{/each}
</ul>Di sini bind:value={$keyword} akan memperbarui store saat input berubah. Lalu filteredProducts otomatis menghitung ulang hasil pencarian. Ini pola yang sangat umum dan mudah dipahami pemula.
Cara Subscribe Store Secara Manual
Di file .svelte, Anda biasanya cukup memakai prefix $. Namun ada kondisi tertentu di mana subscribe manual dibutuhkan, misalnya saat bekerja di file JavaScript biasa, helper function, atau integrasi dengan library lain.
Contoh subscribe manual:
import { cartCount } from '$lib/stores/cart';
const unsubscribe = cartCount.subscribe((value) => {
console.log('Cart count:', value);
});
// panggil jika sudah tidak dibutuhkan
unsubscribe();Di komponen Svelte, penggunaan subscribe manual harus hati-hati agar tidak lupa membersihkan subscription. Jika hanya ingin menampilkan nilai di template, cara paling aman dan singkat tetap memakai $store.
Pola Dasar yang Disarankan untuk Pemula
1. Simpan store di folder terpisah
Gunakan src/lib/stores agar mudah dicari dan dipakai ulang. Hindari membuat store acak di banyak lokasi tanpa pola yang jelas.
2. Mulai dari writable sederhana
Jangan langsung membuat abstraksi terlalu rumit. Jika cukup dengan:
export const count = writable(0);maka itu sudah baik.
3. Pakai derived untuk data turunan
Jika nilai bisa dihitung dari state lain, jangan simpan salinan state yang sama dalam bentuk lain. Lebih baik hitung dengan derived agar konsisten.
4. Bungkus aksi jika update mulai berulang
Kalau banyak komponen memanggil logika update yang sama, pertimbangkan pola factory store seperti contoh createCartCount(). Ini membantu mencegah duplikasi.
5. Pisahkan state UI sederhana dan data server
Store bagus untuk state antarmuka dan state bersama di sisi klien. Tetapi untuk data yang berasal dari server, pertimbangkan juga alur bawaan SvelteKit seperti load agar pengambilan data tetap jelas.
Kesalahan Umum dan Tips Debugging
Lupa import dari svelte/store
Pastikan writable dan derived diimpor dari paket yang benar:
import { writable, derived } from 'svelte/store';Salah memakai $store di luar komponen
Sintaks $cartCount hanya berlaku di file .svelte. Jika Anda berada di file JavaScript biasa, gunakan subscribe atau utilitas lain yang sesuai.
Menyimpan state turunan secara manual
Contoh kesalahan umum adalah menyimpan filteredProducts sebagai store writable lalu lupa memperbaruinya saat keyword berubah. Untuk kasus seperti ini, derived adalah solusi yang lebih aman.
Masalah SSR saat menyentuh API browser
Jika store Anda membaca window, document, atau localStorage saat file diimport, ini bisa bermasalah pada render sisi server. Pindahkan logika tersebut ke sisi klien.
Store terasa terlalu global
Kalau satu store dipakai untuk terlalu banyak hal yang tidak berkaitan, pecah menjadi beberapa store yang lebih kecil. Store yang terlalu besar akan sulit dirawat dan membingungkan.
Penutup
Untuk dasar manajemen state di SvelteKit, memahami writable dan derived sudah sangat cukup untuk banyak kasus nyata. Dengan writable, Anda bisa menyimpan dan mengubah state bersama seperti cart counter dan tema. Dengan derived, Anda bisa membangun nilai turunan seperti label cart atau hasil filter pencarian tanpa harus sinkronisasi manual.
Pola yang paling aman untuk pemula adalah:
- simpan store di
src/lib/stores, - mulai dari store yang sederhana,
- pakai
$storedi komponen, - gunakan
deriveduntuk hasil perhitungan dari store lain.
Jika Anda sudah nyaman dengan pola dasar ini, langkah berikutnya biasanya adalah menyimpan state yang lebih kompleks, menggabungkan store dengan data dari server, atau menambahkan persistensi seperti localStorage. Namun untuk banyak aplikasi kecil sampai menengah, dasar yang dibahas di artikel ini sudah sangat berguna dan sering dipakai sehari-hari.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!