[Vue3실강] 11강 Pinia

youngseo·2022년 6월 8일
post-thumbnail

Pinia

Vue의 공식 상태 관리 라이브러리가 Pinia 로 변경되었습니다 . Pinia는 Vuex 5 RFC 에 설명된 Vuex 5와 거의 동일하거나 향상된 API를 가지고 있습니다. Pinia를 다른 이름의 Vuex 5로 생각할 수 있습니다.

Vuex vs Pinia

⭐Pinia는 TypeScript를 지원합니다.

  • vuex에서 module을 지원하긴 하지만 각각 흩어져있는 moudule파일들에 대한 state의 타입을 추론하는 것이 어려웠습니다.
  • 그런데 Pinia는 defineStore라는 함수를 이용하여 각각의 파일마다 별도의 store를 정의하여 module의 기능을 대신합니다.
  • vuex의 this.$store와는 달리 pinia는 defineStore가 반환하는 hook을 이용하여 store에 아주 쉽게 접근할 수 있습니다.
  • 그렇기에, 반환 된 hook은 내부 구성 요소에 대한 타입을 포함하고 있으며, 타입 추론에 대한 그 어떤 작업도 추가로 필요하지 않습니다.
  • 따라서 타입스크립트를 도입하고 컴포지션 API를 적용하는 경우 그 장점이 확연하게 들어날 수 있습니다.

1. core concepts

vuex에서는core concepts로 state,Getters, Mutations, Actions, Modules 총 5가지 개념을 도입했습니다.

Pinia에서는 state,Getters,action로 세가지 개념을 사용합니다. (모듈화는 필수적으로 적용되게 됩니다.)

mutations이 없어 권한이 없어 사용하기 편한 대신에 그로인해 발생하는 에러에 대한 책임을 져야합니다.

2. pinia 적용

2-1 pinia설치

$ npm i pinia

2-2 store>index.js

🎨차이점

vuex를 사용할 때는 store폴더를 만들어 그 안에 index.js라는 기본 파일을 만들었습니다.

만약, message라는 이름으로 모듈화를 하는 경우 store폴더 안에는 모듈이 하나더라도 message.js와 index.js파일로 총 2개의 파일이 존재해야했습니다.

하지만, pinia는 index.js 없이 모듈화된 파일만 있으면 됩니다.

🎨차이점

또한 vuex에서는 모듈화된 파일의 상단에 namedspaced:true가 필요했습니다. 하지만 피니아는 모듈이 기본 옵션이기에 따로 필요하지 않습니다.

store>message.js

import {defineStore} from 'pinia'

//이름을 가지는 내보내기
//첫번쨰 인수로 사용하고자 하는 모듈의 이름을 넣어줘야합니다
export const useMessageStore = defineStore('message'⭐,{
  //화살표함수로 하면 좋습니다.
  state: () => ({
    message: 'Hello world!'
  }),
  getters: {
    reversedMessage(state) {
      return state.message.split('').reverse().join('')
    }
  },
  actions: {
    reverseMessage() {
      //this로 접근
      this.message = this.message.split('').reverse().join('')
    }
  },
})

🔑이름을 가지는 내보내기를 할 때 보통 이름 앞에 use를 붙여 사용합니다.

🎨공통점 : state

vuex에서는 mutations에서 state에 접근하기 위해 state라는 매개변수를 사용했습니다. 마찬가지로 pinia에서도 getters에서 state에 접근하기 위해 state를 매개변수로 받습니다.

🎨차이점 : context

vuex에서는 actions의 매개변수로 context(={state,getters,commit,dsipatch})를 사용했습니다.

하지만 pinia에서는 this를 통해 보다 편하게 접근을 할 수 있습니다.

2-2 store의 state를 가져오기

🎨vuex에서는

vuex에서는 아래와 같이 state의 정보를 가져올 수 있었습니다.

1) 첫번째 방법
computed: {
  message() {
    return this.$store.state.message.message
  }
}

만약 매핑을 하는 경우 아래와 같이 사용할 수 있었습니다.

2) 두번쨰 방법
import {mapState} from 'vuex'

computed: {
  ...mapState('message', [
      message
    ]),
}

🎨pinia에서는

하지만 pinia에서는 첫번째 방법은 사용을 할 수 없습니다

about.vue

import {mapState} from 'pinia' //1
import {useMessageStore} from '~/store/message' //2

export default {
  computed: {
    ...mapState(useMessageStore, [ //3
      'message'
    ])
  }
}
  1. mapState을 사용하는 경우 마찬가지로 pinia에서 mapState를 가지고 와 등록하면 됩니다.

  2. 단 피니아는 모든 것이 모듈이기 때문에 그 모듈을 직접가져와야합니다.

  3. 그리고 vuex에서는 모듈이름이 들어갔던 자리에 모듈을 통채로 집어넣습니다

2-3 피니아 등록하기

main.js

import { createApp } from 'vue'
import { createPinia } from 'pinia'✅
import router from './routes'
import '~/routes/guards'
import App from './App.vue'

createApp(App)
  .use(createPinia())✅호출합니다
  .use(router)
  .mount('#app')

2-4 연결확인하기

About.vue

<template>
  <h1>About!</h1>
  <RouterLink to="/about/name">
    Name~
  </RouterLink>
  <RouterView />
  <div>{{ message }}</div>
</template>

2-5 store의 getters 가져오기

🎨vuex에서는

import {mapState, mapGetters} from 'vuex'

와 같이 mapGetters를 가져왔습니다

🎨pinia에서는

getter도 mapState에서 가지고 옵니다.

<template>
  <h1>About!</h1>
  <RouterLink to="/about/name">
    Name~
  </RouterLink>
  <RouterView />
  <div>{{ message }}</div>
  <div>{{ reversedMessage }}</div>
</template>
<script>
import {mapState} from 'pinia'
import {useMessageStore} from '~/store/message'

export default {
  computed: {
    ...mapState(useMessageStore, [
      'message',
      'reversedMessage'
    ])
  }
}
</script>

2-5 store의 actions 가져오기

🎨pinia에서는

mapActions에서 actions를 가져올 수 있습니다.

<template>
  <h1>About!</h1>
  <RouterLink to="/about/name">
    Name~
  </RouterLink>
  <RouterView />
  <div>{{ message }}</div>
  <div>{{ reversedMessage }}</div>
  <button @click="reverseMessage">
    Reverse!!
  </button>
</template>
<script>
import {mapState, mapActions✅} from 'pinia'
import {useMessageStore} from '~/store/message'

export default {
  computed: {
    ...mapState(useMessageStore, [
      'message',
      'reversedMessage'
    ])
  },
  methods: {✅
    ...mapActions(useMessageStore,[
      'reverseMessage'
    ])
  }
}
</script>

2-6 mapStores

mapState, mapActions대신 사용할 수 있는 개념이 새로 나왔습니다.

등록하는 방법

<script>
import {mapStores} from 'pinia'
import {useMessageStore} from '~/store/message'

export default {
  computed: {
    ...mapStores([useMessageStore]) 
  },
}
</script>

위와 같이 등록을 해줍니다.

사용하는 방법

<template>
  <h1>About!</h1>
  <RouterLink to="/about/name">
    Name~
  </RouterLink>
  <RouterView />
  <div>{{✅ messageStore.message }}</div>
  <div>{{✅ messageStore.reversedMessage }}</div>
  <button @click="✅messageStore.reverseMessage">
    Reverse!!
  </button>
</template>

useMessageStore에서 use를 뺀 객체데이터를 붙여줍니다.

messageStore라는 이름 범위 안에서 사용을 하기 때문에 관리가 조금 더 용이합니다.

<button @click="messageStore.message='HEROPY?!@'">
  HEROPY
</button>

위와 같이 state의 데이터를 수정해버릴 수도 있습니다.


참고

1개의 댓글

comment-user-thumbnail
2022년 8월 18일

안녕하세요

올려주신 글 잘 보았습니다

궁금한 점이 있어서 댓글을 남깁니다

main.js 자체에서 pinia를 사용하여 store를 수정 할 수 있을까요?

ex) vue로 만들어진 홈페이지나 app을 접속 하면 main에서 아이디값을 localstorage를 확인 후 있으면 로그인 처리한다

이런식으로 하고 싶습니다 가능 할까요?

답글 달기