75 phút
State Management với Pinia
State Management với Pinia
Giới thiệu Pinia
Pinia là state management library chính thức cho Vue.js.
Cài đặt và Cấu hình
Cài đặt
npm install pinia
Cấu hình
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
Tạo Store
Option Stores
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
name: 'My Counter'
}),
getters: {
doubleCount: (state) => state.count * 2,
doubleCountPlusOne() {
return this.doubleCount + 1
}
},
actions: {
increment() {
this.count++
},
decrement() {
this.count--
},
async incrementAsync() {
await new Promise(resolve => setTimeout(resolve, 1000))
this.increment()
}
}
})
Setup Stores
// stores/user.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
const user = ref(null)
const isAuthenticated = computed(() => user.value !== null)
function login(userData) {
user.value = userData
}
function logout() {
user.value = null
}
return {
user,
isAuthenticated,
login,
logout
}
})
Sử dụng Store trong Components
Composition API
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
// Sử dụng storeToRefs để giữ reactivity
const { count, doubleCount } = storeToRefs(counterStore)
const { increment, decrement } = counterStore
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
Options API
<script>
import { mapState, mapActions } from 'pinia'
import { useCounterStore } from '@/stores/counter'
export default {
computed: {
...mapState(useCounterStore, ['count', 'doubleCount'])
},
methods: {
...mapActions(useCounterStore, ['increment', 'decrement'])
}
}
</script>
Advanced Patterns
Multiple Stores
<script setup>
import { useCounterStore } from '@/stores/counter'
import { useUserStore } from '@/stores/user'
const counterStore = useCounterStore()
const userStore = useUserStore()
// Truy cập multiple stores
const combinedData = computed(() => ({
count: counterStore.count,
userName: userStore.user?.name
}))
</script>
Store Subscriptions
// Theo dõi state changes
counterStore.$subscribe((mutation, state) => {
console.log('State changed:', mutation, state)
})
// Theo dõi action calls
counterStore.$onAction(({ name, store, args, after, onError }) => {
console.log('Action called:', name)
after((result) => {
console.log('Action finished:', name, result)
})
onError((error) => {
console.error('Action failed:', name, error)
})
})
Persistence với Pinia Plugin
// plugins/persistence.js
import { createPinia } from 'pinia'
const pinia = createPinia()
pinia.use(({ store }) => {
// Khôi phục state từ localStorage
const savedState = localStorage.getItem(store.$id)
if (savedState) {
store.$patch(JSON.parse(savedState))
}
// Lưu state khi có thay đổi
store.$subscribe((mutation, state) => {
localStorage.setItem(store.$id, JSON.stringify(state))
})
})
export default pinia