·
1 min read

Pinia Tip: Use Setup Stores for More Flexibility

Pinia Tip: Use Setup Stores for More Flexibility Image

Besides Option Stores you can also use Setup Stores to define stores in Pinia. They bring more flexibility as you can create watchers within a store and freely use any composable.

Defining Setup Store

Just like the setup function in the Vue Composition API, a function that sets up reactive properties and methods can be passed, which will return an object containing the properties and methods that should be made available:

useCounterStore.js
export const useCounterStore = defineStore('counter', () => { const count = ref(0) const doubleCount = computed(() => count.value * 2) function increment() { count.value++ } return { count, doubleCount, increment } })

In Setup Stores:

  • ref()s become state properties
  • computed()s become getters
  • function()s become actions

What syntax should I pick?

When it comes to Vue's Composition API and Options API, select the one that you are most familiar with. If you are uncertain, start with the Option Stores.

Using Setup Store

At this point, we only defined the store but it won't be created until use...Store() is called inside of setup():

Component.vue
<script setup> const store = useCounterStore() </script> <template> <span>Counter: {{ store.count }}</span> <span>Double Count: {{ store.doubleCount }}</span> <button @click="store.increment">Increment</button> </template>

Info

The store object has been wrapped with reactive, so there is no need to include .value when using getters, but similar to props in setup, it cannot be destructured. You need to use storeToRefs() to destructure while keeping reactivity.

Bonus Tip

You can use composables that return writable state like VueUse useLocalStorage() directly within the state() function:

useCounterStore.js
export const useCounterStore = defineStore('counter', () => { const counterInfo = useLocalStorage('counterInfo', null) return { counterInfo } })

The same example using Option Store:

useCounterStore.js
export const useCounterStore = defineStore('counter', () => { state: () => ({ // ... counterInfo: useLocalStorage('counterInfo', null), }) })

If you liked this Vue tip, follow me on X to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter:

I will never share any of your personal data. You can unsubscribe at any time.