| name | pinia |
| description | Pinia state management for Vue 3 including store creation, actions, getters, plugins, and DevTools integration. |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep |
| graph | {"domains":["domain:web-development"],"specializations":["specialization:web-development"],"skillAreas":["skill-area:application-state-management","skill-area:vue-components"],"roles":["role:frontend-engineer"],"topics":["topic:flux-pattern"]} |
Pinia Skill
Expert assistance for implementing Pinia state management in Vue 3 applications.
Capabilities
- Create type-safe Pinia stores
- Implement actions for async operations
- Define getters for computed state
- Configure Pinia plugins (persistence, etc.)
- Set up store composition patterns
- Integrate with Vue DevTools
Usage
Invoke this skill when you need to:
- Set up global state management in Vue
- Create feature-specific stores
- Implement persistent state
- Compose multiple stores
- Handle async state operations
Inputs
| Parameter | Type | Required | Description |
|---|
| storeName | string | Yes | Store name (use prefix) |
| stateShape | object | Yes | Initial state structure |
| actions | array | Yes | Store actions |
| getters | array | No | Computed getters |
| persist | boolean | No | Enable persistence |
Configuration Example
{
"storeName": "useUserStore",
"stateShape": {
"user": null,
"isAuthenticated": false
},
"actions": ["login", "logout", "fetchUser"],
"getters": ["fullName", "isAdmin"],
"persist": true
}
Store Patterns
Setup Store (Recommended)
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
interface User {
id: string;
name: string;
email: string;
role: 'user' | 'admin';
}
export const useUserStore = defineStore('user', () => {
const user = ref<User | null>(null);
const loading = ref(false);
const error = ref<string | null>(null);
const isAuthenticated = computed(() => !!user.value);
const isAdmin = computed(() => user.value?.role === 'admin');
const fullName = computed(() => user.value?.name ?? 'Guest');
() {
loading. = ;
error. = ;
{
response = (, {
: ,
: { : },
: .({ email, password }),
});
(!response.) {
();
}
data = response.();
user. = data.;
.(, data.);
} (e) {
error. = (e ).;
e;
} {
loading. = ;
}
}
() {
user. = ;
.();
}
() {
token = .();
(!token) ;
loading. = ;
{
response = (, {
: { : },
});
user. = response.();
} (e) {
();
} {
loading. = ;
}
}
{
user,
loading,
error,
isAuthenticated,
isAdmin,
fullName,
login,
logout,
fetchUser,
};
});
Options Store
import { defineStore } from 'pinia';
interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
export const useCartStore = defineStore('cart', {
state: () => ({
items: [] as CartItem[],
}),
getters: {
totalItems: (state) =>
state.items.reduce((sum, item) => sum + item.quantity, 0),
totalPrice: (state) =>
state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
isEmpty: (state) => state.items.length === 0,
},
actions: {
addItem(item: Omit<, >) {
existing = ..( i. === item.);
(existing) {
existing.++;
} {
..({ ...item, : });
}
},
() {
index = ..( i. === id);
(index > -) {
..(index, );
}
},
() {
item = ..( i. === id);
(item) {
item. = .(, quantity);
(item. === ) {
.(id);
}
}
},
() {
. = [];
},
},
});
Pinia Setup with Plugins
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import App from './App.vue';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
const app = createApp(App);
app.use(pinia);
app.mount('#app');
export const useSettingsStore = defineStore('settings', {
state: () => ({
theme: 'light',
language: 'en',
}),
persist: true,
});
export const useUserStore = defineStore('user', {
state: () => ({
user: null,
token: null,
}),
persist: {
key: 'user-store',
: ,
: [],
},
});
Store Composition
import { defineStore } from 'pinia';
import { useCartStore } from './cart';
import { useUserStore } from './user';
export const useCheckoutStore = defineStore('checkout', () => {
const cart = useCartStore();
const user = useUserStore();
const canCheckout = computed(() => {
return user.isAuthenticated && !cart.isEmpty;
});
async function processCheckout(paymentMethod: string) {
if (!canCheckout.value) {
throw new Error('Cannot checkout');
}
const order = {
userId: user.user!.id,
items: cart.items,
total: cart.totalPrice,
paymentMethod,
};
const response = await fetch('/api/orders', {
method: 'POST',
: { : },
: .(order),
});
(response.) {
cart.();
}
response.();
}
{
canCheckout,
processCheckout,
};
});
Usage in Components
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useUserStore } from '@/stores/user';
const userStore = useUserStore();
// Destructure with reactivity preserved
const { user, isAuthenticated, loading } = storeToRefs(userStore);
// Actions can be destructured directly
const { login, logout } = userStore;
async function handleLogin() {
try {
await login(email.value, password.value);
router.push('/dashboard');
} catch (e) {
// Handle error
}
}
</script>
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="isAuthenticated">
Welcome, {{ user?.name }}
<button @click="logout">Logout</button>
</div>
<LoginForm v-else @submit="handleLogin" />
</template>
Best Practices
- Prefer setup stores for better TypeScript support
- Use storeToRefs for reactive destructuring
- Compose stores for complex features
- Keep stores focused on single concerns
- Use plugins for cross-cutting concerns
Target Processes
- vue-application-development
- nuxt-full-stack
- state-management-setup
- frontend-architecture