[Vue3] Pinia : 4. Pinia를 활용한 상태 관리

gminnimk·2025년 3월 21일

Vue3

목록 보기
32/39

1️⃣ Computed에 대해 잠깐 알아보기

컴포넌트 내부에서 함수를 만들 때 보통 methods에 작성하는데,

실제로는 계산된 값으로 작성할 수도 있습니다.

computed는 컴포넌트 로드 시 한 번 실행되고, 그 결과를 캐싱해두므로

반복 호출해도 내부 코드가 다시 실행되지 않습니다.

Vue2 예시 (Vuex 이전 방식):

computed: {
  now2(){
    return new Date()
  }
},
methods: {
  now(){
    return new Date()
  }
}
  • methods: 호출할 때마다 새로 실행
  • computed: 최초 계산 후 결과를 저장해 재사용

Vue3 <script setup>에서 computed 사용 예시

<script setup>
import { computed } from 'vue'

const now = computed(() => new Date())
</script>

<template>
  <!-- 함수 호출할 때는 소괄호 없이 computed 변수명만 사용 -->
  <div>{{ now }}</div>
</template>

포인트: computed는 함수보다는 계산 결과를 저장하는 "계산 캐시" 역할

<template>
  <div>
    <input v-model="num1" type="number" placeholder="숫자 1" />
    <input v-model="num2" type="number" placeholder="숫자 2" />
    <p>합계: {{ sum }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

// 반응형 변수 선언
const num1 = ref(0)
const num2 = ref(0)

// computed를 사용해 두 숫자의 합계를 계산
const sum = computed(() => {
  return Number(num1.value) + Number(num2.value)
})
</script>

이 코드에서는:

  • computed를 사용해 num1num2의 합계를 계산하는 반응형 값을 정의합니다.
  • 템플릿에서는 v-model을 사용하여 입력 값을 반응형 변수와 바인딩하고, 계산된 합계 sum을 출력합니다.

참고: Vue 공식 문서 및 다양한 Vue3 튜토리얼에서 이와 유사한 예시를 확인할 수 있습니다.


2️⃣ Pinia로 상태(state) 관리 간소화하기

2-1. 기존 Vuex 방식 (Vue2 문법)

Vue 파일 내에서 상태를 꺼내쓸 때

// Vuex 사용 시 (Vue2 문법)
this.$store.state.name

이런 식으로 긴 경로를 사용하게 됩니다.

자주 사용하는 state라면 computed에 넣어두면 조금은 편해집니다.

computed: {
  name(){
    return this.$store.state.name
  }
}

이렇게 하면 템플릿에서는 {{ name }}으로 바로 접근할 수 있습니다.

또, 여러 state를 한 번에 가져오고 싶다면 Vuex의 mapState 함수를 사용할 수 있습니다.

import { mapState } from 'vuex'

computed: {
  ...mapState(['state이름1', 'state이름2']),
  // 또는 이름 변경 가능
  ...mapState({ 작명: 'state이름1' })
}

또한, mutations도 mapMutations를 사용하면

import { mapState, mapMutations } from 'vuex'

computed: {
  ...mapState(['state이름1', 'state이름2'])
},
methods: {
  ...mapMutations(['좋아요', 'setMore'])
}

이렇게 하면 $store.commit('좋아요') 대신 좋아요()로 호출할 수 있습니다.


2-2. Vue3 + Pinia 방식 (리팩토링 후)

Pinia에서는 Vuex의 mapState, mapMutations 등의 별도 헬퍼 함수 없이

스토어 인스턴스를 직접 가져와 사용하면 되며,

storeToRefs를 이용해 상태들을 개별 ref로 변환할 수 있습니다.

예시: Pinia 스토어 정의 (stores/myStore.js)

// stores/myStore.js
import { defineStore } from 'pinia'

export const useMyStore = defineStore('myStore', {
  state: () => ({
    name: 'Pinia 예제',
    state이름1: '값1',
    state이름2: '값2'
  }),
  actions: {
    좋아요() {
      // 기존 commit 대신 직접 액션 실행
      console.log('좋아요 액션 실행')
    },
    setMore(payload) {
      // 추가 액션 처리
      console.log('setMore 호출', payload)
    }
  }
})

예시: Vue 컴포넌트 내에서 Pinia 사용 (Vue3 <script setup>)

<script setup>
import { storeToRefs } from 'pinia'
import { useMyStore } from '@/stores/myStore'

// Pinia 스토어 인스턴스 가져오기
const myStore = useMyStore()
// storeToRefs로 state를 ref로 변환하면, 템플릿에서 바로 사용 가능
const { name, state이름1, state이름2 } = storeToRefs(myStore)

// computed를 따로 작성할 필요 없이, state는 반응형(ref)로 관리됨
// 액션은 함수처럼 직접 호출 가능: myStore.좋아요()
</script>

<template>
  <div>
    <h1>{{ name }}</h1>
    <p>{{ state이름1 }} / {{ state이름2 }}</p>
    <button @click="myStore.좋아요()">좋아요</button>
    <!-- setMore 액션 호출 예시 -->
    <button @click="myStore.setMore('추가 데이터')">setMore 호출</button>
  </div>
</template>

포인트:

  • Vuex에서는 $store.state.name처럼 긴 경로를 사용했지만,
  • Pinia에서는 storeToRefs를 사용하여 간편하게 name 등의 state에 바로 접근할 수 있습니다.
  • 또한, action(이전의 mutations 포함)은 myStore.좋아요()처럼 바로 호출할 수 있어 코드가 훨씬 깔끔해집니다.

📌 정리

  • computed는 Vue 컴포넌트의 계산 결과를 캐싱하는 역할을 하며, <script setup>에서는 import { computed } from 'vue'로 사용합니다.
    • '계산 캐시' 로 이해하기
  • 기존 Vuex에서는 this.$store.statemapState, mapMutations 등을 사용해 상태와 액션을 관리했지만, Pinia에서는 useMyStore()로 스토어 인스턴스를 가져오고, storeToRefs를 사용해 state를 개별 ref로 만들어 템플릿에서 간편하게 사용합니다.
  • Pinia에서는 별도의 헬퍼 함수 없이 액션을 직접 호출할 수 있어 코드가 훨씬 깔끔해집니다.

0개의 댓글