Pinia Replaced Vuex
Simpler API, better TypeScript support, and it just works.
Creating a Store
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
user: null,
loading: false,
}),
getters: {
isLoggedIn: (state) => !!state.user,
fullName: (state) => `${state.user?.firstName} ${state.user?.lastName}`,
},
actions: {
async fetchUser() {
this.loading = true
this.user = await api.getUser()
this.loading = false
},
logout() {
this.user = null
},
},
})
Using the Store
<script setup>
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
// Access state
userStore.user
userStore.isLoggedIn
// Call actions
await userStore.fetchUser()
userStore.logout()
</script>
<template>
<div v-if="userStore.isLoggedIn">
Welcome, {{ userStore.fullName }}
</div>
</template>
Composition API Style
export const useCartStore = defineStore('cart', () => {
const items = ref([])
const total = computed(() =>
items.value.reduce((sum, item) => sum + item.price, 0)
)
function addItem(item) {
items.value.push(item)
}
return { items, total, addItem }
})
When to Use Stores
Use stores for:
- User authentication state
- Shopping cart
- App-wide settings
- Data shared between routes
Don't use for:
- Form state (keep local)
- UI state (modals, dropdowns)
- Data only one component needs
Persisting State
import { defineStore } from 'pinia'
import { useLocalStorage } from '@vueuse/core'
export const useSettingsStore = defineStore('settings', () => {
const theme = useLocalStorage('theme', 'light')
return { theme }
})
