Di pelajaran sebelumnya store keranjang cuma menghitung jumlah dan total. Keranjang sungguhan menyimpan daftar menu: tiap menu bisa ditambah dan dibuang, totalnya dihitung dari daftar itu, dan di akhir hari semuanya dikosongkan. Pelajaran ini melengkapi store-nya: state berupa array, getter dengan computed, action yang menambah dan membuang, storeToRefs, $patch, dan $reset. Bayangin lagi papan di dinding dapur Warung Bu Sri. Sekarang tiap pesanan ditulis satu baris, angka total di bawahnya selalu dijumlah ulang dari baris-baris itu, satu baris bisa dicoret, dan saat warung tutup papannya dihapus bersih seperti pagi hari.
🧪 Tebakan cepat: Store keranjang ditulis gaya setup. Saat warung tutup, kode memanggil
keranjang.$reset(). Di build production, apa yang terjadi pada isi keranjang? Tebak dulu, jawabannya ada di bagian "$patch dan $reset".
Store gaya setup yang lengkap
// stores/keranjang.js
import { ref, computed } from "vue"
import { defineStore } from "pinia"
export const useKeranjangStore = defineStore("keranjang", () => {
const items = ref([])
const meja = ref(null)
let nomor = 0
const total = computed(() => items.value.reduce((jumlah, item) => jumlah + item.harga, 0))
function tambah(menu) {
items.value.push({ id: ++nomor, nama: menu.nama, harga: menu.harga })
}
function hapus(index) {
items.value.splice(index, 1)
}
function kosongkan() {
items.value = []
meja.value = null
}
return { items, meja, total, tambah, hapus, kosongkan }
})
| Kejadian | items |
total |
|---|---|---|
| awal | [] |
0 |
tambah(Nasi Goreng) |
Nasi Goreng 15000 | 15000 |
tambah(Es Teh) |
Nasi Goreng 15000, Es Teh 5000 | 20000 |
hapus(0) |
Es Teh 5000 | 5000 |
kosongkan() |
[] |
0 |
totaladalah getter:computedyang menjumlahhargasemua item.reducemulai dari0, lalu menambahkanitem.hargasatu per satu. Gak ada yang perlu memperbaruitotalsecara manual.tambahmendorong menu baru ke array denganpush.iddarinomormemberi tiap baris:keyyang unik.hapus(index)memotong satu elemen di posisi itu dengansplice(index, 1). Datanya benar-benar berkurang, jadi barisnya hilang dan baris berikutnya naik.- Latihan memakai Pinia asli dengan daftar todo: latihan pertama mengambil
todosdari store lewatstoreToRefs, mendorong teks yang diketik, lalu mengosongkan kolomnya. Latihan kedua menulis store gaya options dengan gettertotaldan action yang membuang satu todo dengansplice(index, 1), lalu$reset()mengembalikan kedua todo awalnya.
Komponen keranjang memakainya begini:
<script setup>
import { storeToRefs } from "pinia"
import { useKeranjangStore } from "../stores/keranjang"
const keranjang = useKeranjangStore()
const { items, total } = storeToRefs(keranjang)
const { hapus } = keranjang
</script>
<template>
<ul>
<li v-for="(item, i) in items" :key="item.id">
{{ item.nama }} Rp{{ item.harga }}
<button @click="hapus(i)">×</button>
</li>
</ul>
<p>Total: Rp{{ total }}</p>
</template>
storeToRefs: state dan getter jadi ref, action diambil langsung
| Ditulis | Isinya |
|---|---|
storeToRefs(keranjang) |
items, meja, total: state dan getter, semuanya ref |
const { hapus } = keranjang |
action-nya, langsung dari store |
storeToRefs()adalah fungsi Pinia untuk destructure store tanpa kehilangan reaktivitas. Karena hasilnya ref, di script dibaca dengan.value(items.value.length), di template langsung ({{ total }}).- Action dilewati oleh
storeToRefs.const { hapus } = storeToRefs(keranjang)memberiundefined, dan tombolnya melempar error karenahapusbukan fungsi. Ambil action dari store-nya sendiri.
$patch dan $reset
Setiap store punya beberapa method bawaan yang diawali $.
keranjang.$patch({ meja: 4 }) // ubah beberapa state sekaligus
keranjang.$patch((state) => { // bentuk fungsi, enak untuk array
state.items.push({ id: 99, nama: "Es Teh", harga: 5000 })
state.meja = 7
})
$patchdengan objek mengganti properti yang disebut saja. Bentuk fungsi menerimastatedan cocok untukpushatausplice. Keduanya dicatat sebagai satu perubahan di devtools.
$reset() mengembalikan state ke nilai awalnya, tapi cuma di store gaya options, karena di sana Pinia bisa memanggil state() lagi:
export const useKeranjangStore = defineStore("keranjang", {
state: () => ({ items: [], meja: null }),
getters: {
total: (state) => state.items.reduce((jumlah, item) => jumlah + item.harga, 0),
},
})
keranjang.$reset() // items: [], meja: null, jadi total 0
Store gaya setup gak punya state() untuk dipanggil ulang. Di build production, $reset() gak melakukan apa-apa: isi keranjang tetap. Itu jawaban tebakannya. Build development malah berhenti dengan pesan ini:
🍍: Store "keranjang" is built using the setup syntax and does not implement $reset().
Untuk store gaya setup, tulis action pengosong sendiri, seperti kosongkan() di atas.
🎯 Store memakai store lain
Sebuah store boleh memanggil store lain, misalnya keranjang yang menolak pesanan saat warung tutup:
export const useKeranjangStore = defineStore("keranjang", () => {
const warung = useWarungStore()
const items = ref([])
function tambah(menu) {
if (!warung.buka) return
items.value.push({ ...menu })
}
return { items, tambah }
})
- Panggil store lain di dalam fungsi setup atau di dalam action, bukan di baris paling atas file.
- Dua store yang saling membaca state di baris setup-nya mendapat store yang belum selesai dibuat, dan nilainya jadi
undefinedatauNaN. Pindahkan bagian bersamanya ke store ketiga.
⚠️ Jebakan yang sering ketemu
$reset()di store gaya setup. Production diam saja, development berhenti. Tulis actionkosongkan()sendiri.- Action lewat
storeToRefs. Hasilnyaundefined. Ambil action langsung dari store. - Menyembunyikan baris, bukan membuang data.
v-ifatauv-showdi baris membuat datanya tetap ada. Buang dengansplice(index, 1)supaya baris berikutnya naik. - Lupa mengosongkan kolom sesudah menambah. Di latihan pertama, sesudah
push, kolomnya harus kembali kosong:input.value = "".
TL;DR: Di store gaya setup, ref adalah state, computed adalah getter (misalnya total dari items.value.reduce(...)), dan fungsi adalah action (push untuk menambah, splice(index, 1) untuk membuang). storeToRefs() mengambil state dan getter sebagai ref tanpa kehilangan reaktivitas; action diambil langsung dari store. $patch mengubah beberapa state sekaligus, lewat objek atau fungsi. $reset() mengembalikan state ke nilai awal, tapi cuma di store gaya options; store gaya setup butuh action pengosong sendiri. Store boleh memakai store lain di dalam setup-nya.