🏠 Home / Hub
🍍 Vue 15 — Pinia State Management
← Vue Menu · ← Prev: Router
Pinia = Vue 3 official state management library (Vuex ကို replace လုပ်တယ်)။ Composition API style, TypeScript friendly, Vue DevTools integration built-in ပါ။
1. Setup
npm install pinia
# main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
2. Define a Store (Setup Store — Recommended)
// stores/useProductStore.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useProductStore = defineStore('products', () => {
// STATE
const products = ref([])
const loading = ref(false)
const error = ref(null)
const search = ref('')
// GETTERS (computed)
const filtered = computed(() =>
products.value.filter(p =>
p.name.toLowerCase().includes(search.value.toLowerCase())
)
)
const count = computed(() => products.value.length)
const inStock = computed(() => products.value.filter(p => p.stock > 0))
// ACTIONS
async function fetchAll() {
loading.value = true
error.value = null
try {
const res = await fetch('/api/products')
products.value = await res.json()
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
}
function addProduct(product) {
products.value.push(product)
}
function updateProduct(updated) {
const idx = products.value.findIndex(p => p.id === updated.id)
if (idx !== -1) products.value[idx] = updated
}
function removeProduct(id) {
products.value = products.value.filter(p => p.id !== id)
}
// $reset() equivalent — restore initial state
function reset() {
products.value = []
loading.value = false
error.value = null
search.value = ''
}
return { products, loading, error, search, filtered, count, inStock,
fetchAll, addProduct, updateProduct, removeProduct, reset }
})
3. Use Store in Components
<script setup>
import { storeToRefs } from 'pinia'
import { useProductStore } from '@/stores/useProductStore'
import { onMounted } from 'vue'
const store = useProductStore()
// storeToRefs: destructure reactive state (stays reactive)
// Actions don't need storeToRefs — destructure directly
const { products, loading, error, search, filtered, count } = storeToRefs(store)
const { fetchAll, addProduct, removeProduct } = store
onMounted(() => fetchAll())
</script>
<template>
<input v-model="search" placeholder="Search...">
<p>{{ count }} products</p>
<p v-if="loading">Loading...</p>
<p v-if="error" style="color:red">{{ error }}</p>
<div v-for="p in filtered" :key="p.id">
{{ p.name }}
<button @click="removeProduct(p.id)">Delete</button>
</div>
</template>
storeToRefs() ကိုသုံးရင် destructured state ကိုပဲ reactive ဖြစ်နေနေမယ်။ actions တွေ (functions) ကို store မှ တိုက်ရိုက် destructure လုပ်ပါ — storeToRefs မလို။
4. Auth Store Example
// stores/useAuthStore.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useAuthStore = defineStore('auth', () => {
const user = ref(JSON.parse(localStorage.getItem('user') || 'null'))
const token = ref(localStorage.getItem('token') || null)
const isLoggedIn = computed(() => !!token.value)
const isAdmin = computed(() => user.value?.role === 'admin')
async function login(email, password) {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
})
if (!res.ok) throw new Error('Invalid credentials')
const data = await res.json()
token.value = data.token
user.value = data.user
localStorage.setItem('token', data.token)
localStorage.setItem('user', JSON.stringify(data.user))
}
function logout() {
token.value = null
user.value = null
localStorage.removeItem('token')
localStorage.removeItem('user')
}
return { user, token, isLoggedIn, isAdmin, login, logout }
})
5. Store Persistence Plugin
# Auto-save store state to localStorage/sessionStorage
npm install pinia-plugin-persistedstate
# main.js
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
# Store — add persist option
export const useCartStore = defineStore('cart', () => {
const items = ref([])
// ...
return { items }
}, {
persist: true, // stores entire state in localStorage
// or:
persist: {
key: 'my-cart',
storage: sessionStorage, // or localStorage
paths: ['items'], // only persist these fields
}
})
6. Cart Store — Real World Example
// stores/useCartStore.js
export const useCartStore = defineStore('cart', () => {
const items = ref([]) // [{product, qty}]
const total = computed(() => items.value.reduce((sum, i) => sum + i.product.price * i.qty, 0))
const itemCount = computed(() => items.value.reduce((sum, i) => sum + i.qty, 0))
function addItem(product, qty = 1) {
const existing = items.value.find(i => i.product.id === product.id)
if (existing) {
existing.qty += qty
} else {
items.value.push({ product, qty })
}
}
function removeItem(productId) {
items.value = items.value.filter(i => i.product.id !== productId)
}
function updateQty(productId, qty) {
const item = items.value.find(i => i.product.id === productId)
if (item) item.qty = Math.max(1, qty)
}
function clear() { items.value = [] }
return { items, total, itemCount, addItem, removeItem, updateQty, clear }
}, { persist: true })
7. Pinia vs Vuex vs Simple ref()
| Scenario | Solution |
| Single component local state | ref() / reactive() in component |
| Parent-child state | Props down, emits up |
| Sibling components | Pinia store (shared) |
| Global app state (user, cart, theme) | Pinia store |
| Async data + loading/error | Pinia action with try/catch |
| Persisted state (localStorage) | Pinia + persistedstate plugin |
| Vuex (legacy) | Migrate to Pinia (simpler, no mutations) |
📌 Study Checklist
- အပေါ်က concept ကို တစ်ကြောင်းချင်းဖတ်ပြီး example ကို ကိုယ်တိုင်ပြန်ရေးကြည့်ပါ။
- Code/command ပါတဲ့ lesson ဆိုရင် value/name/path တစ်ခုခု ပြောင်းပြီး result ဘာကွာလဲ စမ်းပါ။
- မမှတ်မိသေးတဲ့ keyword 3 ခုကို notebook ထဲရေးပြီး နောက် lesson မသွားခင် ပြန်ရှင်းကြည့်ပါ။
- ပြီးရင် Home / Hub ကိုပြန်သွားပြီး next lesson ဆက်သင်ပါ။