Pinia является официальным решением для управления состоянием в приложениях на Vue 3, заменяя Vuex и предлагая более простую и интуитивную архитектуру. В основе Pinia лежит концепция stores — централизованных хранилищ состояния, которые могут использоваться в любом компоненте приложения.
Хранилище в Pinia создается с помощью функции
defineStore. Основные элементы хранилища:
Пример простого хранилища:
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
},
incrementBy(amount) {
this.count += amount
}
}
})
Ключевые моменты:
state всегда является функцией,
возвращающей объект, что обеспечивает независимость экземпляров
хранилища.getters автоматически получают
реактивность и кеширование.actions имеют доступ к
this внутри хранилища, что позволяет изменять состояние
напрямую.Хранилище подключается через функцию useStore в любом
компоненте:
<script setup>
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
function incrementCounter() {
counterStore.increment()
}
</script>
<template>
<div>
<p>Счёт: {{ counterStore.count }}</p>
<p>Удвоенный счёт: {{ counterStore.doubleCount }}</p>
<button @click="incrementCounter">Увеличить</button>
</div>
</template>
Важно: изменения состояния хранилища автоматически отражаются во всех компонентах, использующих это хранилище.
Pinia поддерживает асинхронные операции в actions без
необходимости использовать внешние middleware:
actions: {
async fetchData() {
const response = await fetch('https://api.example.com/data')
this.data = await response.json()
}
}
Асинхронные методы могут напрямую изменять реактивное состояние, что упрощает работу с API и внутренней логикой приложения.
Pinia не ограничивает одним глобальным хранилищем. Каждый store имеет свою область ответственности:
// stores/user.js
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
email: ''
}),
actions: {
setUser(data) {
this.name = data.name
this.email = data.email
}
}
})
Такой подход обеспечивает модульность, улучшает читаемость и тестируемость кода.
Для интеграции Pinia с Vue 3 используется основной экземпляр приложения:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.mount('#app')
После этого любое хранилище можно подключать в компонентах через
useStore.
Pinia поддерживает плагины для сохранения состояния, например, в
localStorage. Использование плагина позволяет автоматически
сохранять и восстанавливать состояние:
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPersist)
В хранилище нужно добавить:
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
persist: true
})
Состояние будет автоматически сохраняться и восстанавливаться при перезагрузке страницы.
Pinia полностью поддерживает TypeScript. Определение хранилища с типами:
interface CounterState {
count: number
}
export const useCounterStore = defineStore<'counter', CounterState>({
id: 'counter',
state: () => ({ count: 0 }),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
Типизация обеспечивает автодополнение, безопасные изменения состояния и ясную структуру хранилища.
Состояние в Pinia полностью реактивно. Можно использовать его в
watch или computed:
import { watch } from 'vue'
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
watch(() => counterStore.count, (newValue, oldValue) => {
console.log(`Счёт изменился с ${oldValue} на ${newValue}`)
})
Любые изменения состояния автоматически триггерят реакции, что упрощает работу с UI и внутренней логикой.
Pinia одинаково удобно использовать как с setup(), так и
с классическим Options API:
export default {
computed: {
count() {
return useCounterStore().count
}
},
methods: {
increment() {
useCounterStore().increment()
}
}
}
Такое сочетание позволяет интегрировать Pinia даже в старые проекты на Vue 3.
getters для производных значений, а
actions для мутаций состояния и асинхронных операций.Pinia обеспечивает современный, легкий и мощный подход к управлению состоянием, значительно упрощая архитектуру Vue-приложений и делая код более предсказуемым и масштабируемым.