
Pinia는 Vue 애플리케이션의 중앙 상태 관리(store)를 간편하게 구현할 수 있도록 도와주는 라이브러리입니다. Pinia에서는 defineStore() 함수를 사용해 store를 정의하며, Options API 방식과 Composition API(Setup) 방식을 모두 지원합니다.
defineStore() 함수를 사용하여 store를 정의합니다.'counter', 'alerts')로 반드시 전달해야 하며, 이 id는 devtools와의 연동에도 사용됩니다.use...Store()와 같이 이름 짓는 것이 관례입니다.import { defineStore } from 'pinia'
// `defineStore()`의 반환값에 원하는 대로 이름을 지을 수 있지만,
// `use`로 시작해 `Store`로 끝나는 Store의 이름을 사용하는 것이 좋습니다.
// (예: `useUserStore`, `useCartStore`, `useProductStore`)
// 첫 번째 인수는 애플리케이션 내 Store의 고유 ID입니다.
export const useAlertsStore = defineStore('alerts', {
// 다른 옵션....
})
Vue의 Options API와 유사하게, store를 state, getters, actions 프로퍼티로 구성합니다.
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0, name: 'Eduardo' }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
참고:
- Options Store는 직관적이고 간단하게 시작할 수 있지만, 유연성 측면에서는 Setup Store에 비해 제한적일 수 있습니다.
Composition API의 setup 함수와 유사한 문법으로 store를 정의합니다.
ref()를 사용해 상태(state)를 정의하고, computed()를 사용해 getter를 구성합니다.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 등)은 반환하지 않아야 하며, 컴포넌트 내부에서 직접 접근하는 것이 좋습니다.
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 추론에 유리합니다.
직접 store의 프로퍼티를 디스트럭처링하면 반응성이 깨질 수 있습니다.
반응성을 유지하며 디스트럭처링하려면 storeToRefs() 함수를 사용해야 합니다.
// ❌ 이렇게 하면 반응성이 깨져서 작동하지 않습니다
// `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>
결론:
사용하고자 하는 방식(Options API vs Composition API)에 따라 선택하면 됩니다. 개인의 프로젝트 스타일에 맞게 선택하고, 필요에 따라 혼용할 수 있습니다.
defineStore()를 사용해 고유 id와 함께 store를 정의합니다.state, getters, actions를 Options API 형태로 작성.<script setup> 내에서 use...Store()로 호출하여 사용.storeToRefs()를 사용해 반응성 유지하며 state를 추출합니다.