[Vue3] Pinia : Store 정의

gminnimk·2025년 3월 22일

Vue3

목록 보기
36/39

Pinia는 Vue 애플리케이션의 중앙 상태 관리(store)를 간편하게 구현할 수 있도록 도와주는 라이브러리입니다. Pinia에서는 defineStore() 함수를 사용해 store를 정의하며, Options API 방식과 Composition API(Setup) 방식을 모두 지원합니다.


1️⃣ Store 정의하기

  • 핵심:
    • defineStore() 함수를 사용하여 store를 정의합니다.
    • 첫 번째 인수는 store의 고유 id (예: 'counter', 'alerts')로 반드시 전달해야 하며, 이 id는 devtools와의 연동에도 사용됩니다.
    • 반환된 함수를 use...Store()와 같이 이름 짓는 것이 관례입니다.
  • 예제 (정의):
    import { defineStore } from 'pinia'
    
    // `defineStore()`의 반환값에 원하는 대로 이름을 지을 수 있지만,
    // `use`로 시작해 `Store`로 끝나는 Store의 이름을 사용하는 것이 좋습니다.
    // (예: `useUserStore`, `useCartStore`, `useProductStore`)
    // 첫 번째 인수는 애플리케이션 내 Store의 고유 ID입니다.
    export const useAlertsStore = defineStore('alerts', {
      // 다른 옵션....
    })
    

2️⃣ Option Store 방식

Vue의 Options API와 유사하게, store를 state, getters, actions 프로퍼티로 구성합니다.

  • 특징:
    • state: 컴포넌트의 data와 같은 역할 (함수로 반환)
    • getters: computed와 유사, state 기반 파생 데이터
    • actions: methods와 유사, 상태 변경을 위한 함수
  • 코드 예제:
    export const useCounterStore = defineStore('counter', {
      state: () => ({ count: 0, name: 'Eduardo' }),
      getters: {
        doubleCount: (state) => state.count * 2,
      },
      actions: {
        increment() {
          this.count++
        },
      },
    })
    

참고:

  • Options Store는 직관적이고 간단하게 시작할 수 있지만, 유연성 측면에서는 Setup Store에 비해 제한적일 수 있습니다.

3️⃣ Setup Store 방식

Composition API의 setup 함수와 유사한 문법으로 store를 정의합니다.

  • 특징:
    • ref()를 사용해 상태(state)를 정의하고, computed()를 사용해 getter를 구성합니다.
    • 함수 내부에 정의된 메서드는 actions로 동작합니다.
    • 모든 state 프로퍼티는 반드시 반환해야 하며, 반환하지 않으면 Pinia, SSR, 개발 도구 등이 제대로 작동하지 않습니다.
  • 코드 예제:
    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 }
    })
    

주의:

  • Setup Store는 Options Store보다 더 많은 유연성컴포저블(composable) 사용이 가능하지만, SSR 환경에서 컴포저블 사용 시 주의해야 합니다.
  • 전역에서 제공된 값(예: 라우터, inject 등)은 반환하지 않아야 하며, 컴포넌트 내부에서 직접 접근하는 것이 좋습니다.

4️⃣ Store 사용하기

Store는 <script setup> 또는 setup() 함수 내에서 use...Store() 함수를 호출하여 사용합니다.

  • 예제:
    <script setup>
    import { useCounterStore } from '@/stores/counter'
    
    // store 인스턴스 생성 (lazy instantiation: 사용될 때 생성)
    const store = useCounterStore()
    
    // store의 state, getters, actions에 직접 접근 가능
    store.increment()
    </script>
    

TIP:

  • 아직 <script setup>을 사용하지 않는 경우, Pinia의 map 헬퍼를 활용하여 store를 컴포넌트에 연결할 수 있습니다.
  • 각 store는 별도의 파일로 분리하여 정의하는 것이 번들러의 코드 분할 및 TypeScript 추론에 유리합니다.

5️⃣ Store에서의 디스트럭처링(비구조화)과 반응성 유지

직접 store의 프로퍼티를 디스트럭처링하면 반응성이 깨질 수 있습니다.

반응성을 유지하며 디스트럭처링하려면 storeToRefs() 함수를 사용해야 합니다.

  • 디스트럭처링(Destructuring)은 구조화된 배열 또는 객체를 Destructuring(비구조화, 파괴)하여 개별적인 변수에 할당하는 것
  • 잘못된 예제 (반응성 상실):
    // ❌ 이렇게 하면 반응성이 깨져서 작동하지 않습니다
    // `props`를 디스트럭처링 하는 것과 같습니다
    const { name, doubleCount } = store
    name // 항상 "Eduardo" 입니다
    doubleCount // 항상 0 입니다
    
  • 올바른 예제 (반응성 유지):
    <script setup>
    import { useCounterStore } from '@/stores/counter'
    import { storeToRefs } from 'pinia'
    
    const store = useCounterStore()
    const { name, doubleCount } = storeToRefs(store)
    // 이제 name과 doubleCount는 반응형 ref로 사용 가능
    
    // actions는 그대로 디스트럭처링 가능
    const { increment } = store
    </script>
    

6️⃣ Options Store vs Setup Store

  • Options Store:
    • 사용법이 간단하여 초보자에게 직관적입니다.
    • state, getters, actions를 명확하게 구분하여 관리합니다.
  • Setup Store:
    • Composition API의 장점을 그대로 활용할 수 있습니다.
    • 더 많은 유연성을 제공하며, 컴포저블(composable)을 자유롭게 사용할 수 있습니다.
    • SSR 등 특정 상황에서는 설정에 주의해야 합니다.

결론:

사용하고자 하는 방식(Options API vs Composition API)에 따라 선택하면 됩니다. 개인의 프로젝트 스타일에 맞게 선택하고, 필요에 따라 혼용할 수 있습니다.


📌 정리

  • Store 정의:
    • defineStore()를 사용해 고유 id와 함께 store를 정의합니다.
  • 옵션 방식:
    • state, getters, actions를 Options API 형태로 작성.
  • Setup 방식:
    • setup 함수 내에서 reactive state, computed, actions를 정의하고 반환.
  • Store 사용:
    • <script setup> 내에서 use...Store()로 호출하여 사용.
  • 디스트럭처링:
    • storeToRefs()를 사용해 반응성 유지하며 state를 추출합니다.
  • 선택:
    • Options Store는 직관적, Setup Store는 유연성 제공.

출처: Pinia 공식 문서 (한국어)

0개의 댓글