Pinia: управління станом у Vue.js
Що таке Pinia?
Pinia — це офіційна бібліотека управління станом для Vue.js (яка замінює Vuex). Вона забезпечує простий, типобезпечний спосіб управління глобальним станом з повною підтримкою Composition API та DevTools.
Визначення магазину
typescript
// stores/counter.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// Стиль Composition API (рекомендується)
export const useCounterStore = defineStore('counter', () => {
// Стан
const count = ref(0)
const name = ref('Counter')
// Геттери (computed)
const doubleCount = computed(() => count.value * 2)
// Дії (функції)
function increment() {
count.value++
}
function decrement() {
count.value--
}
async function fetchCount() {
const response = await fetch('/api/count')
count.value = await response.json()
}
return { count, name, doubleCount, increment, decrement, fetchCount }
})Стиль Options API
typescript
// stores/user.ts
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
email: '',
isLoggedIn: false,
}),
getters: {
initials: (state) => state.name.split(' ').map(n => n[0]).join(''),
},
actions: {
async login(email: string, password: string) {
const user = await api.login(email, password)
this.name = user.name
this.email = user.email
this.isLoggedIn = true
},
logout() {
this.$reset() // Скидає стан до початкових значень
},
},
})Використання магазину в компонентах
vue
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
// ✅ Використовуйте storeToRefs для реактивного деструктуризації
const { count, doubleCount } = storeToRefs(counterStore)
// Дії можна деструктуризувати безпосередньо
const { increment, decrement } = counterStore
</script>
<template>
<div>
<p>Кількість: {{ count }}</p>
<p>Подвійна: {{ doubleCount }}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>storeToRefs
typescript
// ❌ Деструктуризація втрачає реактивність
const { count } = useCounterStore()
// count — це просто число, не реактивне
// ✅ storeToRefs зберігає реактивність
const { count } = storeToRefs(useCounterStore())
// count — це Ref<number>, реактивнеСпілкування між магазинами
typescript
// stores/cart.ts
import { defineStore } from 'pinia'
import { useUserStore } from './user'
export const useCartStore = defineStore('cart', () => {
const items = ref<CartItem[]>([])
function checkout() {
const userStore = useUserStore() // Використання іншого магазину
if (!userStore.isLoggedIn) {
throw new Error('Необхідно увійти в систему')
}
// Обробка оформлення замовлення...
}
return { items, checkout }
})Pinia vs Vuex
| Особливість | Pinia | Vuex |
|---|---|---|
| Стиль API | Composition + Options | Тільки Options |
| Мутації | ❌ Не потрібні | Обов'язкові |
| TypeScript | ✅ Повна підтримка | ⚠️ Складна типізація |
| Модулі | Плоскі магазини (простіше) | Вкладені модулі |
| DevTools | ✅ Повна підтримка | ✅ Повна підтримка |
| Розмір пакету | ~1.5KB | ~10KB |
| Підтримка Vue 2 | Через плагін | Нативно |
Важливо:
Pinia є рекомендуємим управлінням станом для Vue 3. Використовуйте стиль Composition API (defineStore з функцією setup) для найкращої підтримки TypeScript. Завжди використовуйте storeToRefs() при деструктуризації стану/геттерів для збереження реактивності. Pinia простіша за Vuex — без мутацій, плоскі магазини та відмінна інференція TypeScript.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.