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:
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 becomestate
propertiescomputed()
s becomegetters
function()
s becomeactions
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()
:
<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>
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:
export const useCounterStore = defineStore('counter', () => {
const counterInfo = useLocalStorage('counterInfo', null)
return { counterInfo }
})
The same example using Option Store:
export const useCounterStore = defineStore('counter', () => {
state: () => ({
// ...
counterInfo: useLocalStorage('counterInfo', null),
})
})
If you liked this Vue tip, follow me on BlueSky to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter :