Introduction
Pinia has pushed Vuex out in Vue 3 and risen as the most popular state management package. The article is going to introduce some advanced features in Pinia.
Setup Store
The Setup store
allows to use store similar as <script setup />
Setup store
는 `option store` 와 달리 `
Compare with option store
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const name = ref('Eduardo')
const doubleCount = computed(() => count.value * 2)
const increament() => {
count.value++
}
return { count, name, doubleCount, increment }
})
The Setup store
is a great feature, but I am using option store
because many examples are written by option store
.
Many references are also written by option store
storeToRefs
The storeToRefs
allows to use Destructing assignment for state and getters in store and they can be updated .Vue
file directrly.
const { count, doubleCount } = storeToRefs(useCounterStore())
count.value = 100
It's wrapped by ref
, reactivity API, so it's easy to update value without mutation.
For the Action, storeToRefs()
is not necessary.
Subscription
The Subscription feature provide better performence than watch. The Subscription feature can watch both timing that state is updating or action is called
State
counterStore.$subscribe((mutation, state) => {
// import { MutationType } from 'pinia'
mutation.type // 'direct' | 'patch object' | 'patch function'
// Store id
mutation.storeId
// mutation.type === 'patch object'일때만 사용 가능함
mutation.payload // store.$patch()로 들어옴
console.log('state is changed', state)
})
The $subscribe
will fire when one of state is update.
See more about state subscription
Action
const counterStore = uesCounter()
const unsubscribe = counterStore.$onAction(
({
name, // name of the action
store, // store instance, same as `someStore`
args, // array of parameters passed to the action
after, // hook after the action returns or resolves
onError, // hook if the action throws or rejects
}) => {
// a shared variable for this specific action call
const startTime = Date.now()
// this will trigger before an action on `store` is executed
console.log(`Start "${name}" with params [${args.join(', ')}].`)
// this will trigger if the action succeeds and after it has fully run.
// it waits for any returned promised
after((result) => {
console.log(
`Finished "${name}" after ${
Date.now() - startTime
}ms.\nResult: ${result}.`
)
})
// this will trigger if the action throws or returns a promise that rejects
onError((error) => {
console.warn(
`Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
)
})
}
)
// manually remove the listener
unsubscribe()
The example code is from official document
The $onAction
will fire when one of actions is called
See more about state subscription
Middleware
Although there is exact middleware that official document explains, there is a way to make featre like middleware
pinia.use(({ store }) => {
store.$subscribe(() => {
// react to store changes
})
store.$onAction((store, name, args) => {
// react to store actions
})
})
The $subscribe
and $onAction
in pinia will watch when one of states or action is changed or called about all stores
Persist
There are 2 ways to save state permanently.
Localstorage
Simply, save data to localstorage and get from localstorage.
export const useCounterStore = defineStore('counter', {
state: () => ({
count: localStorage.getItem('pinia/counter/count'),
name: useLocalStorage('pinia/counter/name', 'bob').
}),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
localStorage.setItem('counter/count', this.count)
},
},
})
To delete saved data, go to F12
-> Application -> Local Storage.
In addition, it's allowed to use useLocalStroage()
in VueUse package. Look at the name in state
Use with Subscribtion
counterStore.$subscribe((mutation, state) => {
localStorage.setItem('pinia/counter/count', state.counter)
})
Auto save feature can be developed by using The $subscribe
explained above
Package
Introducing Package also use same way, but it's much easier. Click the Official document to see more details
First of all, install package
npm i pinia-plugin-persistedstate
yarn add pinia-plugin-persistedstate
pnpm i pinia-plugin-persistedstate
Register package plugin to pinia
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
Set persist in store.
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0, name: 'Eduardo' }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
persist: true
})
Simply add persist: true
to store. States will be saved localstorage automatically.
Other storages are also supported.
persist: {
storage: persistedState.sessionStorage,
},
Devtool
You can debug all store with Chrome Vue devtool. Chrome extension Just install the extension and click the pinia tab.