Skip to main content
Practice Problems

Pinia: state management in Vue.js

What is Pinia?

Pinia is the official state management library for Vue.js (replacing Vuex). It provides a simple, type-safe way to manage global state with full Composition API and DevTools support.


Defining a Store

typescript
// stores/counter.ts import { defineStore } from 'pinia' import { ref, computed } from 'vue' // Composition API style (recommended) export const useCounterStore = defineStore('counter', () => { // State const count = ref(0) const name = ref('Counter') // Getters (computed) const doubleCount = computed(() => count.value * 2) // Actions (functions) 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 Style

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() // Resets state to initial values }, }, })

Using a Store in Components

vue
<script setup> import { useCounterStore } from '@/stores/counter' import { storeToRefs } from 'pinia' const counterStore = useCounterStore() // ✅ Use storeToRefs for reactive destructuring const { count, doubleCount } = storeToRefs(counterStore) // Actions can be destructured directly const { increment, decrement } = counterStore </script> <template> <div> <p>Count: {{ count }}</p> <p>Double: {{ doubleCount }}</p> <button @click="increment">+</button> <button @click="decrement">-</button> </div> </template>

storeToRefs

typescript
// ❌ Destructuring loses reactivity const { count } = useCounterStore() // count is just a number, not reactive // ✅ storeToRefs preserves reactivity const { count } = storeToRefs(useCounterStore()) // count is a Ref<number>, reactive

Store-to-Store Communication

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() // Use another store if (!userStore.isLoggedIn) { throw new Error('Must be logged in') } // Process checkout... } return { items, checkout } })

Pinia vs Vuex

FeaturePiniaVuex
API styleComposition + OptionsOptions only
Mutations❌ Not neededRequired
TypeScript✅ Full support⚠️ Complex typing
ModulesFlat stores (simpler)Nested modules
DevTools✅ Full support✅ Full support
Bundle size~1.5KB~10KB
Vue 2 supportVia pluginNative

Important:

Pinia is the recommended state management for Vue 3. Use the Composition API style (defineStore with setup function) for best TypeScript support. Always use storeToRefs() when destructuring state/getters to preserve reactivity. Pinia is simpler than Vuex — no mutations, flat stores, and excellent TypeScript inference.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems