Pinia란?
Vue 버전 2를 사용할 때는 주로 상태 관리를 Vuex로 처리했는데, Vue3 or Composition API이 출시되면서 Pinia라는 상태 관리 모듈이 추가되었다. Vuex의 단점으로는 TS와 같이 설계하기가 어려움이 있었는데 (문법이나 Type 등에서), 이 점이 많이 개선되었다고 한다.
그 외에도 장점이 꽤 많은 것 같은데, 공식 문서를 기반으로 Pinia의 장점은 무엇이 있는지 알아보자.
공식 문서 소개 페이지에 있는 내용이다. 직관적이고, 안전하고, Devtools 지원에, 확장, 모듈식, 가벼움 등등의 장점이 적혀있다.
이 내용만 보고서는 Vuex와 비교 했을 때 정확히 어떤 차이가 있고 어느 정도 더 좋은지 알기 어려운듯 싶다. 직접 사용해보면서 겪어보자!
// npm i pinia
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
app.mount('#app')
Vue3 프로젝트를 생성하고 pinia를 설치했다. pinia를 사용하기 위해서는 main.js에 app.use를 통해 등록해줘야 한다.
등록 후에는 store 폴더에 파일을 만들어서 모듈처럼 사용이 가능하다.
export const useStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
doubleCount: state => state.count * 2
},
actions: {
increment() {
this.count ++;
}
}
})
위 코드는 state, getters, actions를 선언하여 사용하는 방식인데 Vuex와 매우 비슷하다.
mutations가 없는데 pinia에서는 mutations을 사용하지 않는다고 한다.
위 방식이 외에 Composition API와 비슷한 방식으로도 사용이 가능하다.
import { defineStore } from "pinia";
import { computed, ref } from "vue";
export const useCounterStore = defineStore('counter', () => {
const count = ref(2);
const name = ref('ethan');
const doubleCount = computed(() => count.value * 2);
const increment = () => count.value++;
return { count, name, doubleCount, increment };
})
Composition API 혹은 Vue3을 사용해보신 분이라면 굉장히 익숙하게 다가올 코드다. Composable처럼 정의하여 사용이 가능하다.
이렇게 사용할 경우 Vue Devtools에서 state, getters 구분이 되나? 싶은데 실제로 테스트 해봤을 때 구분이 된다.
똑똑하네...
Component에서는 어떻게 사용하는지 살펴보자. Store 뿐만 아니라 Props 등 Vue에서는 변수 선언 시 반응형이 깨지지 않도록
신경을 써줘야한다.
setup() {
const counterStore = useCounterStore();
const { increment, name, count, doubleCount } = counterStore;
return {
name,
count,
doubleCount,
increment
}
}
만약 위 코드처럼 구조분해할당을 통해 변수를 선언하고 return 해줄 경우 imcrement를 통해
count 값을 변경해도 화면에서는 변경되지 않는다.
스크린 샷을 보면 화면에는 2,4로 표시되지만 실제 pinia에는 12,24로 되어 있는 걸 볼 수 있다.
그러면 반응형이 깨지지 않도록 하려면 어떻게 해야 할까? 아래처럼 작성하면 된다.
setup() {
const counterStore = useCounterStore();
const { name, count, doubleCount } = storeToRefs(counterStore);
const { increment } = counterStore;
return {
name, count, doubleCount,
increment
}
}
storeToRefs 안에 store를 넘겨준 후 구조분해할당을 통해 가져올 경우 반응형이 꺠지지 않아서 정상적으로 동작이 된다.
SSR 환경에서는 설정 방법이 조금 다른 것 같은데, 다음 포스팅에서는 SSR 환경 및 더욱 심화적인 내용을 작성할 예정이다.