Files
2nd/10_Wiki/Topic_Programming/Frontend/Pinia.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

230 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
// 매 reactivity 매 유지: storeToRefs 매 ref 변환
const { count, doubled } = storeToRefs(store)
// actions 매 destructure OK (not reactive)
const { increment } = store
</script>
<template>
<button @click="increment">{{ count }} (×2 = {{ doubled }})</button>
</template>
```
### 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<CartItem[]>([])
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<User | null>(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 |