Pinia Actions, Getters & Stores
Organize a Pinia store with the Options-style syntax, understand getters vs actions, and compose stores together.
The Options-Style Store
Alongside the setup-store syntax from the previous lesson, Pinia also supports an Options-style definition, structured similarly to the Options API — many teams find this form especially readable for stores.
// stores/cart.jsimport { defineStore } from 'pinia';
export const useCartStore = defineStore('cart', { state: () => ({ items: [], }), getters: { totalPrice: (state) => state.items.reduce((sum, item) => sum + item.price, 0), }, actions: { addItem(item) { this.items.push(item); }, removeItem(id) { this.items = this.items.filter((item) => item.id !== id); }, },});State, Getters, and Actions Explained
| Block | Purpose | Composition API Equivalent |
|---|---|---|
| state | The store's raw reactive data | ref() / reactive() |
| getters | Cached, derived values from state | computed() |
| actions | Methods that read and mutate state, sync or async | plain functions |
Async Actions
Actions can be async functions directly — Pinia has no special API for this; it's just a plain async method using this to access and mutate state.
actions: { async fetchCart() { const res = await fetch('/api/cart'); this.items = await res.json(); },},Using One Store Inside Another
A store can call another store's composable inside its own actions — a common pattern when, say, a cart store needs to check the current user from a user store.
import { useUserStore } from './user';
export const useCartStore = defineStore('cart', { actions: { async checkout() { const userStore = useUserStore(); if (!userStore.isLoggedIn) { throw new Error('Must be logged in to checkout'); } // ... proceed with checkout }, },});Common Beginner Mistakes
Arrow functions don't bind their own this, so this.items inside one would be undefined — use a regular method shorthand (addItem(item) { ... }) for actions.
It technically works, but funneling all mutations through actions keeps state changes traceable and centralized — especially valuable as a store grows.
FAQs
Both are fully supported and equally valid; the setup-store syntax is a bit more flexible (it can use any Composition API feature directly), while the Options-style is often considered clearer for simple stores.
Yes — getters are cached based on their dependencies, exactly like a computed property, and only recompute when the underlying state they read changes.
Summary
The Options-style store organizes state, getters, and actions explicitly, and stores can call one another cleanly. With routing and state management covered, the next section turns to data fetching and forms.