Pinia — современная библиотека управления состоянием для Vue.js, пришедшая на смену Vuex. Она обеспечивает реактивное управление данными, модульность и простоту интеграции с Vue 3. Основные преимущества Pinia — легкость в использовании, поддержка TypeScript и строгая типизация, а также оптимизация для Composition API.
Для установки Pinia используется менеджер пакетов npm или yarn:
npm install pinia
или
yarn add pinia
После установки необходимо интегрировать Pinia в проект Vue. В
основном файле приложения (main.js или
main.ts) подключение выглядит следующим образом:
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');
Здесь создается экземпляр Pinia и регистрируется в приложении через
метод use(). Этот шаг обязателен, иначе магазины Pinia не
смогут быть использованы в компонентах.
Магазин Pinia — это объект, который управляет состоянием, геттерами и
действиями. Для его создания используется функция
defineStore.
Пример базового магазина:
// stores/counter.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++;
},
decrement() {
this.count--;
}
}
});
Ключевые моменты:
defineStore('имя', {...}) — создает магазин с
уникальным идентификатором.state — функция, возвращающая объект состояния.getters — вычисляемые свойства, которые автоматически
реактивны.actions — методы для изменения состояния. В отличие от
Vuex, здесь нет необходимости использовать мутации.После создания магазина его можно использовать в компонентах через Composition API:
<template>
<div>
<p>Count: {{ counter.count }}</p>
<p>Double Count: {{ counter.doubleCount }}</p>
<button @click="counter.increment">Increment</button>
<button @click="counter.decrement">Decrement</button>
</div>
</template>
<script>
import { useCounterStore } from '../stores/counter';
export default {
setup() {
const counter = useCounterStore();
return { counter };
}
}
</script>
Важно: каждый вызов useCounterStore() возвращает
тот же экземпляр магазина, если Pinia подключена к
приложению. Это гарантирует единое состояние во всех компонентах.
Pinia отлично интегрируется с Vue Router. Магазины можно использовать для управления глобальным состоянием маршрутов или авторизации. Например:
import { createRouter, createWebHistory } from 'vue-router';
import { useAuthStore } from './stores/auth';
import Home from './views/Home.vue';
import Login from './views/Login.vue';
const routes = [
{ path: '/', component: Home, meta: { requiresAuth: true } },
{ path: '/login', component: Login }
];
const router = createRouter({
history: createWebHistory(),
routes
});
router.beforeEach((to, from, next) => {
const authStore = useAuthStore();
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
next('/login');
} else {
next();
}
});
export default router;
Такой подход позволяет держать логику авторизации централизованной в Pinia, не дублируя её в компонентах.
Pinia поддерживает подключение плагинов для расширения функциональности:
Пример подключения persisted state:
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
После подключения любой магазин можно настроить на автоматическое сохранение:
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
persist: true
});
Для удобства и масштабируемости рекомендуется:
stores/counter.js, stores/auth.js).actions — они должны
изменять только состояние магазина.Pinia удобно использовать для хранения данных, получаемых с API. Пример асинхронного действия:
export const useTodoStore = defineStore('todo', {
state: () => ({ todos: [] }),
actions: {
async fetchTodos() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos');
this.todos = await response.json();
}
}
});
Асинхронные действия выполняются напрямую в actions, без
необходимости создавать отдельные модули или middleware, что упрощает
архитектуру приложения.
Pinia сочетает простоту и мощь, позволяя создавать масштабируемые и легко поддерживаемые приложения на Vue.js. Правильная организация магазинов, использование геттеров и действий обеспечивает чистый, реактивный и предсказуемый поток данных.