0
0
VueHow-ToBeginner · 3 min read

How to Use Actions in Pinia for Vue State Management

In Pinia, actions are methods inside a store used to change state or run async code. You define actions as functions inside the actions property of your store, then call them like regular methods from your components.
📐

Syntax

Actions are defined inside the actions object of a Pinia store. Each action is a function that can modify the store's state or perform asynchronous tasks. You call actions using the store instance.

Parts explained:

  • defineStore: Creates a store.
  • state: Holds reactive data.
  • actions: Contains methods to update state or run logic.
  • this inside actions: Refers to the store instance, so you can access state and other actions.
typescript
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    },
    async incrementAsync() {
      await new Promise(resolve => setTimeout(resolve, 1000))
      this.count++
    }
  }
})
💻

Example

This example shows a Pinia store with a counter state and two actions: one to increment immediately and one to increment after a delay. The component calls these actions to update the count.

vue
import { createApp } from 'vue'
import { createPinia, defineStore } from 'pinia'

const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    },
    async incrementAsync() {
      await new Promise(resolve => setTimeout(resolve, 1000))
      this.count++
    }
  }
})

const App = {
  template: `
    <div>
      <p>Count: {{ counter.count }}</p>
      <button @click="counter.increment">Increment</button>
      <button @click="counter.incrementAsync">Increment Async (1s delay)</button>
    </div>
  `,
  setup() {
    const counter = useCounterStore()
    return { counter }
  }
}

const app = createApp(App)
app.use(createPinia())
app.mount('#app')
Output
Count: 0 [Click Increment] Count: 1 [Click Increment Async] (wait 1 second) Count: 2
⚠️

Common Pitfalls

Common mistakes when using actions in Pinia:

  • Not using this inside actions to access state, causing errors.
  • Trying to mutate state outside actions or state property, which breaks reactivity.
  • Forgetting to call async actions with await if you need to wait for completion.
  • Defining actions outside the actions object, which Pinia won't recognize.
typescript
import { defineStore } from 'pinia'

// Wrong: Mutating state directly outside actions
export const useWrongStore = defineStore('wrong', {
  state: () => ({ count: 0 }),
  // increment is not inside actions, so won't work
  increment() {
    this.count++
  }
})

// Right: Actions inside actions object
export const useRightStore = defineStore('right', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    }
  }
})
📊

Quick Reference

ConceptDescriptionExample
defineStoreCreates a Pinia storeconst useStore = defineStore('id', {...})
stateReactive data inside storestate: () => ({ count: 0 })
actionsMethods to change state or run logicactions: { increment() { this.count++ } }
Calling actionsUse store instance methodsstore.increment()
Async actionsActions can be async functionsasync incrementAsync() { await ...; this.count++ }

Key Takeaways

Define actions inside the actions object to change state or run async code.
Use this inside actions to access and modify the store's state.
Call actions from components using the store instance methods.
Avoid mutating state outside actions to keep reactivity intact.
Async actions should be awaited if you need to wait for their completion.