Pinia

Simplify Vue.js state management with Pinia automation and integration tools

Pinia is a community skill for managing application state in Vue.js projects using the Pinia store library, covering store definition, reactive state, getters, actions, and plugin integration for scalable frontend state management.

What Is This?

Overview

Pinia provides tools for organizing and sharing reactive state across Vue components through a lightweight store system. It covers store definition that creates modular state containers with typed properties, reactive state that updates components when store data changes, getters that compute derived values with built-in caching, actions that encapsulate state mutations with full TypeScript support, and plugin integration that extends stores with persistence and devtools features. The skill enables developers to build maintainable Vue applications with predictable state flows.

Who Should Use This

This skill serves Vue.js developers sharing state across multiple components, frontend teams migrating from Vuex to Pinia, and developers building TypeScript-first Vue applications with type-safe state management.

Why Use It?

Problems It Solves

Component prop drilling becomes unmanageable when nested components need shared data. Vuex stores require verbose boilerplate with mutations and module namespacing that increases complexity. TypeScript integration with Vuex requires manual type declarations that drift from actual store shape. State management logic scattered across components makes it difficult to track data changes.

Core Highlights

Store builder defines typed state containers with reactive properties and computed getters. Action handler encapsulates state mutations with async support and error handling. Plugin system extends stores with persistence and devtools integration. Composition API support enables store usage inside setup functions with full reactivity.

How to Use It?

Basic Usage

// Pinia store definition
import { defineStore } from
  'pinia'
import { ref, computed }
  from 'vue'

export const useCartStore =
  defineStore('cart', () => {
    const items = ref<
      CartItem[]
    >([])

    const total = computed(
      () => items.value
        .reduce(
          (sum, item) =>
            sum +
            item.price *
            item.qty,
          0))

    const itemCount =
      computed(() =>
        items.value
          .reduce(
            (sum, item) =>
              sum +
              item.qty,
            0))

    function addItem(
      product: Product
    ) {
      const existing =
        items.value.find(
          i => i.id ===
            product.id)
      if (existing) {
        existing.qty++
      } else {
        items.value.push({
          ...product,
          qty: 1 })
      }
    }

    function removeItem(
      id: string
    ) {
      items.value =
        items.value
          .filter(
            i => i.id !==
              id)
    }

    return {
      items, total,
      itemCount,
      addItem,
      removeItem }
  })

Real-World Examples

// Auth store with API
import { defineStore } from
  'pinia'
import { ref, computed }
  from 'vue'

interface User {
  id: string
  email: string
  name: string
}

export const useAuthStore =
  defineStore('auth', () => {
    const user = ref<
      User | null>(null)
    const token = ref<
      string | null>(null)
    const loading =
      ref(false)

    const isLoggedIn =
      computed(() =>
        !!token.value)

    async function login(
      email: string,
      password: string
    ) {
      loading.value = true
      try {
        const res =
          await fetch(
            '/api/login',
            { method: 'POST',
              headers: {
                'Content-Type':
                  'application/'
                  + 'json' },
              body:
                JSON.stringify(
                  { email,
                    password }
                ) })
        const data =
          await res.json()
        user.value =
          data.user
        token.value =
          data.token
      } finally {
        loading.value =
          false
      }
    }

    function logout() {
      user.value = null
      token.value = null
    }

    return {
      user, token,
      loading,
      isLoggedIn,
      login, logout }
  })

Advanced Tips

Use the composition API syntax with setup functions for better TypeScript inference compared to options API. Subscribe to store actions with $onAction to implement cross-cutting concerns like analytics without modifying store logic. Use pinia-plugin-persistedstate to sync store data to localStorage across page reloads.

When to Use It?

Use Cases

Manage user authentication state including tokens and profile data shared across navigation guards and components. Build a shopping cart store that persists items across sessions with computed totals. Share form state between multi-step wizard components without prop drilling.

Related Topics

Pinia, Vue.js, state management, Vuex, composition API, reactive stores, and frontend architecture.

Important Notes

Requirements

Vue 3 application with Pinia installed and registered as a plugin. TypeScript configuration for type-safe store definitions. Build tool like Vite or webpack with Vue plugin support.

Usage Recommendations

Do: organize stores by domain feature rather than data type to keep related logic together. Use getters for computed values instead of deriving state in components. Keep actions focused on single operations with clear names describing the state transition.

Don't: create a monolithic store for all application state since this defeats the modular design. Mutate store state directly from components outside actions since this makes changes harder to track. Store derived data when getters can compute it from existing values to avoid synchronization issues.

Limitations

Store reactivity depends on Vue's reactivity system which does not track property additions on plain objects without using reactive wrappers. Server-side rendering requires careful store hydration to avoid state mismatches between server and client. Plugin ecosystem is smaller than Vuex with fewer pre-built extensions for specialized functionality.