Vue의 Pinia 고급 기능 소개
Introduction
Pinia 는 Vue 3에서 Vuex를 밀어내고 가장 인기 있는 Statement manage 패키지로 올라섰습니다. 또한 한국어로 잘 번역되어 있기 때문에 한국에서 많이 사용하고 있습니다. 이 게시물은 Pinia를 조금 더 잘 사용하는 방법에 대해 설명할 것입니다.
Setup Store
`Setup store`는 `option store` 와 달리 `<script setup />` 처럼 사용 할 수 있게 합니다.
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 }
})
그러나 저는 option store만을 사용하고 있습니다. 대부분의 예제가 `option store` 로 쓰여져 있기 때문입니다.
storeToRefs
`storeToRefs` 함수 는 store 내에 존재하는 state와 getters 데이터를 Destructing하여 .Vue 파일 내에서변경할 수 있도록 도와줍니다.
const { count, doubleCount } = storeToRefs(useCounterStore())
count.value = 100
ref, reactivity API로 되어 있기 때문에, .value로 쉽게 변경이 가능합니다.
Action은 storeToRefs()로 Destructing 하지않아도 됩니다.
Subscription
State 혹은 Action이 변경되었을 때 다른일을 하고 싶으면 subscribe를 사용 할 수 있습니다. Watch보다 더 나은 Performence를 제공합니다.
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)
})
store의 `$subscribe`는 state의 데이터가 변경되었을 때 작동합니다.
https://pinia.vuejs.org/core-concepts/actions.html#Subscribing-to-actions
Pinia | The intuitive store for Vue.js
Intuitive, type safe, light and flexible Store for Vue
pinia.vuejs.org
Action
const counterStore = uesCounter()
const unsubscribe = counterStore.$onAction(
({
name, // Action 명
store, // Store 인스턴스
args, // action arguement 배열
after, // Action의 return 혹은 resolve 된 후 작동
onError, // 에러가 발생했거나, rejected 된 후 작동
}) => {
// 테스트용 시작 시간
const startTime = Date.now()
// 테스트용 메시지
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.error(
`Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
)
})
}
)
// 수동으로 구독 해제
unsubscribe()
예제 코드는 공식문서의 코드를 조금 변형했습니다.
store의 `$onAction`는 action이 호출 되었을 때 작동합니다.
https://pinia.vuejs.org/core-concepts/actions.html#Subscribing-to-actions
Pinia | The intuitive store for Vue.js
Intuitive, type safe, light and flexible Store for Vue
pinia.vuejs.org
Middleware
정확히는 공식문서에서 말하는 Middleware는 따로 없습니다. 하지만 Middleware처럼 사용 할 수 있는 방법은 존재합니다.
pinia.use(({ store }) => {
store.$subscribe(() => {
// react to store changes
})
store.$onAction((store, name, args) => {
// react to store actions
})
})
pinia의 use 함수내에서 subscriptin과 onAction 을 이용하여 middleware 같이 작동 시킬 수 있습니다.
`$subscribe()` 메소드는 store가 변경되었을 때 작동하며, `$onAction()` 메소드는 store의 action이 호출 되었을 때 작동합니다.
Persist
영구적으로 보관 하는 방법은 2가지가 있습니다. 직접 구현 방법과 패키지를 사용하는 방법입니다.
Localstorage
간단한 방법으로 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)
},
},
})
저장된 데이터를 삭제하기 위해서는 개발자 도구 (F12) -> Application -> Local Storage 에서 데이터들을 삭제하시면 됩니다.
추가적으로, VueUse 패키지의 `useLocalStroage()` 를 사용 할 수 도 있습니다. 예제는 state의 name을 확인해주세요.
Subscribtion과 같이 사용하기
counterStore.$subscribe((mutation, state) => {
localStorage.setItem('pinia/counter/count', state.counter)
})
위에서 설명한 `$subscribe`와 같이 사용하면 state 자동 저장 기능을 만들 수 있습니다.
Package
패키지는 위와 비슷한 방법으로 저장하고 있으나, 더 쉬운 방법으로 저장할 수 도와줍니다.
https://prazdevs.github.io/pinia-plugin-persistedstate/
Home | pinia-plugin-persistedstate
pinia-plugin-persistedstate Configurable persistence and rehydration of Pinia stores.
prazdevs.github.io
우선 패키지를 설치해주세요.
npm i pinia-plugin-persistedstate
yarn add pinia-plugin-persistedstate
pnpm i pinia-plugin-persistedstate
pinia에 plugin을 등록해줘야합니다
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
Persist 지정하기
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0, name: 'Eduardo' }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
persist: true
})
간단하게 `persist: true`를 추가하면 store내 모든 정보가 local storage에 저장됩니다.
localstorage는 clientside사용이 됩니다. Nuxt에서 다른 storage를 사용하고 싶을 경우
persist: {
storage: persistedState.sessionStorage,
},
위와 같은 방법으로 변경하면 됩니다.
Devtool
Chrome Vue devtool 확장프로그램을 이용하여 모든 store를 디버깅 할 수 있습니다.
https://devtools.vuejs.org/guide/installation.html#chrome
Installation | Vue Devtools
Installation Previous version If you want to install the previous version of the devtools (v5), see here. Chrome Install the extension on the Chrome Web Store: Install on Chrome Beta To install the beta version of the devtools, remove or disable any existi
devtools.vuejs.org
References
Pinia | The intuitive store for Vue.js
Intuitive, type safe, light and flexible Store for Vue
pinia.vuejs.org