Pinia
Pinia is a store library for Vue which allows you to share a state across components.
Note
We have used Composition API in this cheatsheet as it is recommended.
In Setup Stores
ref()
s become state properties.
computed()
s become getters.
function()
s become actions.
Define Store
export const useCounterStore = defineStore('counter', () => {
// States
const count = ref(0)
const name = ref('Eduardo')
// Getters
const doubleCount = computed(() => count.value * 2)
// Actions
function increment() {
count.value++
}
return { count, name, doubleCount, increment }
})
Use store
<script setup>
import { useCounterStore } from '@/stores/counter'
// access the `store` variable anywhere in the component ✨
const store = useCounterStore()
// Another way to use the store
// Destructuring from the store
// This will also extract refs for properties added by plugins
// but skip any action or non reactive (non ref/reactive) property
const { name, doubleCount } = storeToRefs(store)
// the increment action can just be destructured
const { increment } = store
</script>
States
Define a state
export const useCounterStore = defineStore('counter', () => {
// States
const count = ref(0)
return { count }
})
Accessing the States
<script setup>
const store = useCounterStore()
console.log(store.count)
</script>
Resetting the States
In Setup Stores, you need to create your own $reset()
method
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function $reset() {
count.value = 0
}
})
Mutating the state
We use $patch
method for mutating the state.
<template>
<button @click="store.$patch({ count: 12 })">patch</button>
</template>
Replacing the state
<template>
<button @click="store.$state = { count: 12 }">Replace</button>
</template>
Subscribing to the state
You can watch the state and its changes through the $subscribe()
method of a store.
store.$subscribe((mutation, state) => {
// import { MutationType } from 'pinia'
mutation.type // 'direct' | 'patch object' | 'patch function'
// same as cartStore.$id
mutation.storeId // 'cart'
// only available with mutation.type === 'patch object'
mutation.payload // patch object passed to cartStore.$patch()
// persist the whole state to the local storage whenever it changes
localStorage.setItem('counter', JSON.stringify(state))
})
Store computed Properties aka Getters
Getters are exactly the equivalent of computed values for the state of a Store.
Define a Getter
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
return { count, doubleCount }
})
Accessing Getters
<script setup>
import { useCounterStore } from './counterStore'
const store = useCounterStore()
</script>
<template>
<p>Double count is {{ store.doubleCount }}</p>
</template>
Accessing Other Getters
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const doubleCountPlusOne = computed(() => doubleCount.value + 1)
return { count, doubleCount, doubleCountPlusOne}
})
Accessing Other Store Getters
import { useOtherStore } from './other-store'
export const useStore = defineStore('main', {
const otherGetter = computed(() => {
const otherStore = useOtherStore()
return state.localData + otherStore.data
})
})
Store methods aka Actions
Actions are the equivalent of methods in components.
Defining an action
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
Accessing Actions
<script setup>
import { useCounterStore } from '@/stores/TaskStore.js';
const counterStore = useCounterStore()
</script>
<template>
<button @click="counterStore.increment">increment</button>
</template>
Accessing other store actions
import { useAuthStore } from './auth-store'
export const useSettingsStore = defineStore('settings', {
const preferences = ref([])
const fetchPreferences = () => {
const auth = useAuthStore()
if(auth.isAuthenticated)
preferences = await fetchPreferences()
else
throw new Error('User must be authenticated')
}
})
Plugin
A Pinia plugin is a function that optionally returns properties to be added to a store. It takes one optional argument, a context:
export function myPiniaPlugin(context) {
context.pinia // the pinia created with `createPinia()`
context.app // the current app created with `createApp()` (Vue 3 only)
context.store // the store the plugin is augmenting
context.options // the options object defining the store passed to `defineStore()`
// ...
}
pinia.use(myPiniaPlugin)
import { markRaw } from 'vue'
// adapt this based on where your router is
import { router } from './router'
pinia.use(() => ({ hello: 'world' }))
pinia.use(({ store }) => {
store.router = markRaw(router)
})
pinia.use(({ store }) => {
store.$subscribe(() => {
// react to store changes
})
store.$onAction(() => {
// react to store actions
})
})