[VueJS] Pinia 특정 Store의 상태(State) 초기화 하기 ($reset)
특정 Store State Reset
vuex에서 특정 Store의 상태를 초기화하기 위해서는 말 그대로 초기 상태의 객체를 가지고 덮어 씌우는 작업을 하는 방법이 존재했다.(예를 들어 lodash의 cloneDeep 사용)
그러나 특이하게도 Pinia에서는 특정 Store State의 Reset 메서드를 제공해주고 있다.
Pinia에서는 Store를 정의하는 방법이 두가지가 존재하는데, 각각의 방법에 따라 Reset 방법에 대해 알아보자.
Option Stores (Object Syntax)
Options API, Vuex 에서 사용하는 방식과 동일한 구조의 Option Stores 방식부터 알아보자.
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0, name: 'Eduardo' }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
이 Option Stores에서는 Store State를 초기화하는 방법이 매우 간단하다.
공식문서에서도 안내해주고 있는데, 아래와 같은 방식으로 사용해주면 된다.
const store = useStore()
store.$reset()
실제로 $reset() 메서드를 제공해주고 있기 때문에 메서드만 호출해주면 상태가 전부 초기상태로 되돌아간다.
아래 코드는 실제 테스트를 진행하면서 사용한 코드이다.
<template>
<div class="reset">
{{ count }} : {{ doubleCount }}
<button @click="store.increment">increment</button>
<button @click="store.$reset">reset</button>
</div>
</template>
<script setup lang="ts">
import { useCounterStore } from "@/store";
import { storeToRefs } from "pinia";
const store = useCounterStore();
const { count, doubleCount } = storeToRefs(store);
</script>
실제로 매우 간단한데, 이러면 왜 굳이 Store를 정의하는 두 가지 방법에 대해 따로따로 안내하는지 의문이 들 수 있다.
다음 셋업 스토어를 통해 사용하는 방법에 대해 알아보면서 의문을 해결해보자.
Setup Stores (Function Syntax)
vuex에서는 불가능하며, Pinia에서 Composition API와 동일한 구조로 정의한 Store이다.
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const name = ref('Eduardo')
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, name, doubleCount, increment }
})
자 그럼 만약에 여기서 위에서 설명한 것과 같이 store.$reset()을 실행하게 되면 어떤 일이 발생할까?
아주 깔끔하게 에러가 발생한다.
🍍: Store "counter" is build using the setup syntax and does not implement $reset().
왜 이런 에러가 발생하는 걸까? 분명 공식문서에서 사용하라는 대로 사용했을 뿐일 텐데.
그래서 해당 $reset() 메서드에 대해 자세히 알아보기 위해 API 문서를 살펴보았다.
https://pinia.vuejs.org/api/interfaces/pinia._StoreWithState.html#reset
이 문서를 살펴보면 에러의 원인이 적혀있었는데,
Resets the store to its initial state by building a new state object.
TODO: make this options only
options에서만 사용이 가능한 메서드였던 것이었다.
그래서 Setup Stores 방식에서 사용하려 하니까 에러가 발생할 수밖에...
뭐 언젠가는 추가될 수도 있겠지만 이 게시글을 작성하는 현재에는 에러가 발생하는 것은 분명하다.
그래서 검색 결과 매우 간단한 해결방법을 찾아내었는데,
사실 방법 자체는 vuex에서 사용하던 초기화 방식과 크게 다른 점은 없다.
▷ reset-store.ts
import { cloneDeep } from "lodash";
import type { StoreGeneric } from "pinia";
// export default function resetStore({ store }: { store: StoreGeneric }) {
// const initialState = structuredClone(store.$state);
// store.$reset = () => store.$patch(structuredClone(initialState));
// }
export default function resetStore({ store }: { store: StoreGeneric }) {
const initialState = cloneDeep(store.$state);
store.$reset = () => store.$patch(cloneDeep(initialState));
}
lodash의 cloneDeep을 사용해주면 되는데, Pinia에 등록된 $reset의 동작원리를 바꾼다고 생각하면 된다.
그리고 main.ts에서 Pinia 플러그인으로 resetStore를 등록해주면 된다.
lodash의 cloneDeep 말고도 structuredClone을 사용할 수도 있는데,
실제로 structuredClone을 사용해보니까 TypeScript에서 제대로 지원을 안 해줘서 그냥 lodash로 갈아탔다.
(알아보니까 structuredClone의 경우 TS 4.7 이상부터 사용 가능하다고 한다. 본문에서 사용하던 버전은 4.5였다.)
▷ main.ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { createPinia } from "pinia";
import resetStore from "./reset-store";
const pinia = createPinia();
pinia.use(resetStore);
createApp(App).use(pinia).use(router).mount("#app");
이런 식으로 등록만 해주면 이제 별 에러 없이 Setup Stores에서도 사용이 가능하다.
자세한 내용은 아래 참고 글을 확인해보도록 하자.
참고 : https://dev.to/the_one/pinia-how-to-reset-stores-created-with-functionsetup-syntax-1b74
참고: https://pinia.vuejs.kr/guide/core-concepts/#option-stores
참고: https://pinia.vuejs.org/core-concepts/state.html