Belajar Vue - State Management Modern
Series/Belajar Vue/Episode 10
Episode 10 of 24

Belajar Vue - State Management Modern

Episode ini membahas Pinia, state manager resmi Vue: definisi store dengan state, getters, dan actions, plugin Pinia untuk ekstensi, perbedaan local state dan global store, serta best practices untuk normalisasi data dan modular stores di aplikasi besar.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Saat aplikasi tumbuh, beberapa state dibutuhkan di banyak komponen yang berjauhan — misalnya data user yang dipakai di header, halaman profil, dan menu. Mengoper lewat props akan berantakan; menyimpan di komponen root juga rapuh. Jawabannya: state management global lewat sebuah store.

Episode 10 membahas Pinia, state manager resmi Vue yang lahir dari pengalaman Vuex. Kita bedah konsep store dengan state, getters, dan actions, plugin Pinia untuk memperluas kemampuan, pembagian local state vs global store, dan best practices untuk normalisasi serta modularisasi store di aplikasi besar.

Pinia sebagai State Manager Resmi

Install dan Setup

Pasang Pinia dan daftarkan sebagai plugin:

Install Pinia
npm install pinia
JSSetup Pinia
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
 
const app = createApp(App);
app.use(createPinia());
app.mount("#app");

createPinia() membuat instance Pinia yang didaftarkan lewat app.use. Setelah itu, store bisa dibuat dan dipakai di komponen mana pun.

Pinia menggunakan pattern yang mirip composable. Store didefinisikan dengan defineStore:

JSStore keranjang
import { defineStore } from "pinia";
import { ref, computed } from "vue";
export const useKeranjangStore = defineStore("keranjang", () => {
  const items = ref([]);
  const totalHarga = computed(() =>
    items.value.reduce((total, item) => total + item.harga, 0)
  );
  function tambah(item) {
    items.value.push(item);
  }
  return { items, totalHarga, tambah };
});

defineStore("keranjang", ...) membuat store dengan nama unik keranjang. Setup store memakai composition API: items sebagai state, totalHarga sebagai getter, dan tambah sebagai action.

State, Getters, dan Actions

State: Data Pusat

State adalah data reaktif yang dimiliki store secara global. Beda dengan local state, state store bisa diakses komponen mana pun tanpa prop drilling.

Getters: Nilai Turunan

Getters menghitung nilai dari state, setara computed:

JSGetter tambahan
export const useKeranjangStore = defineStore("keranjang", () => {
  const items = ref([]);
  const jumlahItem = computed(() => items.value.length);
  function itemById(id) {
    return items.value.find((item) => item.id === id);
  }
  return { items, jumlahItem, itemById };
});

jumlahItem adalah getter murni, sedangkan itemById(id) adalah getter berparameter — keduanya memakai computed atau fungsi biasa untuk menurunkan data.

Actions: Logika Mutasi

Actions adalah tempat seluruh mutasi state dan logika async berada:

JSAction async
export const useKeranjangStore = defineStore("keranjang", () => {
  const items = ref([]);
  async function muatDariServer() {
    const res = await fetch("/api/keranjang");
    items.value = await res.json();
  }
  return { items, muatDariServer };
});

muatDariServer() memuat data dari API dan memperbarui state. Seluruh perubahan state melalui actions membuat alur data dapat dilacak di satu tempat.

Memakai Store di Komponen

JSMemakai store di komponen
<script setup>
import { useKeranjangStore } from "../stores/keranjang";
const store = useKeranjangStore();
</script>
 
<template>
  <p>Total item: {{ store.jumlahItem }}</p>
</template>

useKeranjangStore() mengambil instance store; akses state lewat store.xxx dan panggil action lewat store.tambah(...). Store bersifat reactive sehingga UI ikut diperbarui.

Local State vs Global Store

Kapan Memakai yang Mana

Rule paling penting dalam state management: tidak semua state perlu global.

  • Local state: data yang hanya dipakai satu komponen — buka/tutup modal, nilai form, tab aktif. Simpan di ref biasa.
  • Global store: data yang dipakai banyak komponen atau dipertahankan antar halaman — sesi user, keranjang, preferensi.

Menyimpan terlalu banyak ke store membuat store membengkak dan sulit diuji. Mulailah dari local state, dan pindahkan ke store hanya ketika benar-benar dibutuhkan bersama.

Best Practices untuk Store Besar

Normalisasi State

Saat data berelasi, simpan dalam bentuk normal agar tidak duplikat:

JSState ternormalisasi
export const useProdukStore = defineStore("produk", () => {
  const byId = ref({});
  const semuaId = ref([]);
 
  function setProduk(list) {
    byId.value = Object.fromEntries(list.map((p) => [p.id, p]));
    semuaId.value = list.map((p) => p.id);
  }
 
  return { byId, semuaId, setProduk };
});

byId memetakan id ke objek, semuaId menyimpan urutan. Peta byId.value = Object.fromEntries(...) menghindari duplikasi data — teknik yang akan kalian pakai untuk data yang di-update sering.

Modular Stores

Bagi store per domain, bukan satu store raksasa:

  • src/stores/user.js untuk domain user
  • src/stores/keranjang.js untuk keranjang
  • src/stores/produk.js untuk produk
  • src/stores/notifikasi.js untuk notifikasi

Setiap store fokus pada satu domain dan bisa saling memakai lewat useOtherStore().

Plugin Pinia

Plugin memperluas semua store sekaligus, misalnya untuk persistence:

JSPlugin Pinia sederhana
import { piniaPluginPersist } from "./plugins/persist";
const pinia = createPinia();
pinia.use(piniaPluginPersist);

pinia.use(plugin) meregistrasi plugin yang membungkus lifecycle store. Pattern ini digunakan untuk persistence ke localStorage, logging aksi, atau sinkronisasi multi-tab — akan kita perluas di episode 14.

Penutup

Episode 10 mengajarkan state management modern dengan Pinia: definisi store memakai setup syntax dengan state, getters, dan actions, plugin untuk ekstensi, aturan jelas kapan state lokal dan kapan global, serta normalisasi dan modularisasi untuk aplikasi besar.

Inti yang harus dibawa pulang:

  • Pinia adalah state manager resmi Vue 3.
  • Store dibangun dengan defineStore dan setup syntax.
  • State untuk data, getters untuk turunan, actions untuk mutasi.
  • Normalisasi state memakai byId untuk menghindari duplikasi.
  • Pisahkan store per domain dan pakai plugin untuk kebutuhan lintas store.

Di episode 11 selanjutnya kita membahas forms dan validation — penanganan form dengan v-model, pattern validasi dengan VeeValidate atau Vuelidate, dynamic forms dengan custom validation rules, serta accessibility dan umpan balik pengguna pada form.

Belajar Vue - State Management Modern | Belajar Vue