--- id: wiki-2026-0508-pinia title: Pinia category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Vue Store, Pinia Store] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [vue, state-management, frontend] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: TypeScript framework: Vue 3 / Pinia 2 --- # Pinia ## 매 한 줄 > **"매 Vue 3 매 official state management — 매 Vuex 4 후속, 매 Composition API native + 매 TypeScript-first"**. Eduardo San Martin Morote 매 2019 발표 매 Vue Core 팀 채택, 매 store 매 composable function 매 표현 매 boilerplate 90% 감소, 매 2026 매 Vue 표준 store library. ## 매 핵심 ### 매 vs Vuex - **No mutations**: 매 actions 가 directly state 수정 — 매 mutation indirection 제거. - **Flat stores**: 매 nested module 매 X — 매 cross-store import 매 graph 형성. - **Type inference**: 매 zero manual typing — 매 store usage 매 fully typed. - **Devtools**: 매 timeline + state inspect + time-travel 지원. ### 매 store kinds - **Options Store**: `state`, `getters`, `actions` — 매 Vuex-like familiar shape. - **Setup Store**: `ref`/`computed`/`function` — 매 Composition API native. ### 매 응용 1. SPA global state (auth, user prefs). 2. Server-side rendering (Nuxt 3 매 native integration). 3. Cross-component caching (API result, derived state). 4. Plugin extension (persistedstate, undo/redo). ## 💻 패턴 ### Setup store (modern preferred) ```ts // stores/counter.ts import { defineStore } from 'pinia' import { ref, computed } from 'vue' export const useCounterStore = defineStore('counter', () => { const count = ref(0) const doubled = computed(() => count.value * 2) function increment() { count.value++ } function reset() { count.value = 0 } return { count, doubled, increment, reset } }) ``` ### Options store ```ts export const useUserStore = defineStore('user', { state: () => ({ user: null as User | null, loading: false, }), getters: { isLoggedIn: (s) => s.user !== null, displayName: (s) => s.user?.name ?? 'Guest', }, actions: { async login(creds: Credentials) { this.loading = true try { this.user = await api.login(creds) } finally { this.loading = false } }, logout() { this.user = null }, }, }) ``` ### Component usage ```vue ``` ### App setup (Vue 3) ```ts // main.ts import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const app = createApp(App) app.use(createPinia()) app.mount('#app') ``` ### Cross-store usage ```ts import { useAuthStore } from './auth' export const useCartStore = defineStore('cart', () => { const auth = useAuthStore() // 매 다른 store 매 import + use const items = ref([]) async function checkout() { if (!auth.isLoggedIn) throw new Error('Login required') return api.checkout(auth.user!.id, items.value) } return { items, checkout } }) ``` ### $patch 매 batch update ```ts const store = useUserStore() store.$patch({ loading: false, user: newUser }) // 매 single devtools entry // or function form for complex mutations store.$patch((state) => { state.cart.push(item) state.lastUpdated = Date.now() }) ``` ### $subscribe 매 store mutation 감지 ```ts store.$subscribe((mutation, state) => { localStorage.setItem('cart', JSON.stringify(state)) }, { detached: true }) ``` ### Plugin (persistedstate) ```ts import { createPinia } from 'pinia' import piniaPersist from 'pinia-plugin-persistedstate' const pinia = createPinia() pinia.use(piniaPersist) // store 정의 시: export const useUserStore = defineStore('user', { state: () => ({ token: '' }), persist: true, // localStorage 매 자동 sync }) ``` ### SSR (Nuxt 3) ```ts // composables/useAuth.ts export const useAuthStore = defineStore('auth', () => { const user = ref(null) // 매 Nuxt 3 매 자동 hydration — server 매 set 한 state 매 client 매 transfer return { user } }) ``` ### Testing ```ts import { setActivePinia, createPinia } from 'pinia' import { beforeEach, expect, test } from 'vitest' beforeEach(() => setActivePinia(createPinia())) test('counter increments', () => { const store = useCounterStore() expect(store.count).toBe(0) store.increment() expect(store.count).toBe(1) expect(store.doubled).toBe(2) }) ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Vue 3 new project | Pinia (default) | | Vuex 4 migration | Pinia (incremental, alias module) | | Composition API preference | Setup store | | Vuex-familiar team | Options store | | Component-local state | `ref`/`reactive` (no store) | | Server state caching | TanStack Query / 매 store 의 X | | SSR (Nuxt) | Pinia (built-in support) | **기본값**: 매 setup store + TypeScript + storeToRefs. ## 🔗 Graph - 부모: [[State Management]] - 변형: [[Vuex]] (predecessor) · [[프론트엔드 및 UIUX 표준|Redux]] · [[Zustand]] · [[Jotai]] - 응용: [[Nuxt]] - Adjacent: [[Composition-API]] ## 🤖 LLM 활용 **언제**: 매 Vue 3 global state, 매 cross-component sharing, 매 Nuxt 3 SSR state, 매 Vuex migration target. **언제 X**: 매 component-local state (ref 만 충분), 매 server cache (TanStack Query 적합), 매 React project (Zustand/Redux). ## ❌ 안티패턴 - **storeToRefs 없이 destructure**: 매 reactivity loss — 매 `const { count } = store` 의 X. - **Store action 매 component logic 침범**: 매 store 매 단순 state holder 매 됨 — 매 business logic 매 store 에 응집. - **Nested store hierarchy 시도**: 매 flat 의 X — 매 cross-import 매 graph 형성. - **Mutation pattern 의 반복**: 매 Vuex habit — 매 action 에서 직접 state 수정 OK. - **매 component 매 store instance 다중 생성**: 매 useStore() 매 singleton — 매 매 호출 동일 instance. ## 🧪 검증 / 중복 - Verified (Pinia 2.x docs, Vue.js official). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — setup/options store + cross-store + SSR + plugin patterns |