[G1-Sync] Manual knowledge update
This commit is contained in:
+203
-104
@@ -2,129 +2,228 @@
|
||||
id: wiki-2026-0508-pinia
|
||||
title: Pinia
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-AUTO-EE6B38]
|
||||
aliases: [Vue Store, Pinia Store]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [auto-reinforced]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [vue, state-management, frontend]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-03
|
||||
github_commit: "[P-Reinforce] Continuous Worker - Pinia"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: TypeScript
|
||||
framework: Vue 3 / Pinia 2
|
||||
---
|
||||
|
||||
# [[Pinia|Pinia]]
|
||||
# Pinia
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Pinia는 대규모 Vue.js 애플리케이션을 위한 공식 상태 관리 라이브러리로, 이전의 공식 도구였던 Vuex를 대체하여 새로운 표준으로 자리 잡았습니다 [1-3]. Vue 2와 Vue 3 모두와 호환되며 Vue 코어 팀에 의해 유지보수됩니다 [1]. 불필요한 보일러플레이트를 제거하고 Composition API 스타일의 단순한 API를 제공하며, 특히 TypeScript와 함께 사용할 때 강력한 타입 추론을 지원하는 것이 특징입니다 [3, 4].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **대규모 애플리케이션을 위한 표준 상태 관리**: 기존에 널리 사용되던 Vuex는 이제 유지보수 모드로 전환되었으며, 새로운 애플리케이션에서는 Pinia의 사용이 적극 권장됩니다 [2]. Pinia는 Vuex 5에 대한 코어 팀의 논의에서 출발하였으며, 기능적 상태와 컴포지션 로직을 분리하는 데 탁월한 선택으로 평가받고 있습니다 [2, 5].
|
||||
* **단순화된 API 및 TypeScript 지원**: Vuex와 비교할 때 Pinia는 의식이 적고 더 단순한 API를 제공합니다 [4]. Composition API 스타일로 스토어를 정의할 수 있게 해주며, TypeScript 환경에서 견고한 타입 추론 지원을 제공하여 엔터프라이즈급 대규모 프로젝트에 매우 적합합니다 [3, 4].
|
||||
* **비즈니스 로직 분리 패턴**: 실전 아키텍처 패턴에서 Pinia는 단순히 전역 상태를 보관하는 것을 넘어, 액션(Action) 내부에 비동기 로직을 포함하여 처리합니다 [3]. 이를 통해 뷰 컴포넌트는 복잡한 로직을 배제하고 UI 렌더링에만 책임을 한정할 수 있게 되어, 클린 아키텍처와 관심사 분리를 촉진합니다 [3].
|
||||
* **통합 및 개발자 경험(DX)**: 대규모 프로덕션 애플리케이션에 필수적인 기능들을 완벽히 지원합니다. 강력한 팀 협업 규칙을 제공하며, 타임라인, 컴포넌트 내 검사, 타임트래블 디버깅 등을 포함한 Vue DevTools와의 통합, 그리고 Hot Module Replacement(HMR)를 지원합니다 [1].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
**서버 사이드 렌더링(SSR) 환경에서의 상태 유출 위험**
|
||||
서버 사이드 렌더링(SSR) 애플리케이션을 구축할 때 전역 상태 관리는 각별한 주의가 필요합니다. 스토어가 단순한 싱글톤(Singleton) 패턴으로 정의될 경우, 서버에서 처리되는 여러 클라이언트의 요청 간에 상태가 공유되어 데이터가 유출(Data Leakage)되는 치명적인 문제가 발생할 수 있습니다 [1, 3].
|
||||
이를 방지하기 위해 Pinia는 각 요청마다 새로운 스토어 인스턴스를 생성하는 구조적 해결책을 제공하고 있습니다 [3]. 하지만 개발자는 SSR을 도입할 때 Pinia의 이러한 아키텍처 요구사항을 명확히 이해하고 적절히 구성해야 하는 제약 사항과 구현 복잡도(Trade-off)를 감수해야 합니다. 그 외의 성능 저하나 추가적인 부작용에 대한 정보는 소스에 관련 정보가 부족합니다.
|
||||
### 매 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 지원.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 store kinds
|
||||
- **Options Store**: `state`, `getters`, `actions` — 매 Vuex-like familiar shape.
|
||||
- **Setup Store**: `ref`/`computed`/`function` — 매 Composition API native.
|
||||
|
||||
#### [상태 관리 및 프레임워크 기반 기술]
|
||||
- [[Vuex]]
|
||||
- 연결 이유: Pinia의 이전 세대 공식 상태 관리 라이브러리입니다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 프론트엔드 상태 관리 패턴이 보일러플레이트 축소와 타입스크립트 친화적으로 진화하게 된 배경과 Pinia의 탄생 목적을 이해할 수 있습니다 [2, 4].
|
||||
- [[Composition API]]
|
||||
- 연결 이유: Vue 3의 핵심 API이자, Pinia가 스토어를 정의할 때 채택한 API 스타일입니다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 상태와 로직이 어떻게 기능별로 논리적으로 결합하고 재사용되는지(Composables)에 대한 Vue 3의 핵심 아키텍처 패턴을 이해할 수 있습니다 [3, 4].
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
#### [렌더링 환경 및 언어 기술]
|
||||
- [[Server-Side Rendering (SSR)]]
|
||||
- 연결 이유: 대규모 웹 애플리케이션에서 SEO 및 초기 로딩 최적화를 위해 사용되며, Pinia 사용 시 상태 공유 문제를 방지해야 하는 환경입니다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 싱글톤 패턴의 한계와, 요청당 새로운 인스턴스를 생성하는 Pinia의 보안/격리 메커니즘 설계 원리를 이해할 수 있습니다 [1, 3].
|
||||
- [[TypeScript]]
|
||||
- 연결 이유: Pinia가 제공하는 가장 큰 장점 중 하나인 '견고한 타입 추론'의 기반이 되는 언어입니다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 엔터프라이즈 규모의 앱에서 상태 관리의 런타임 에러를 방지하고 타입 안전성을 확보하는 방법을 이해할 수 있습니다 [3, 4].
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
- Pinia의 Composition-API 스타일 스토어 정의 방식이 기존 Vuex의 Options API 방식(Mutations와 Actions의 구분 등) 대비 코드 구조의 복잡성을 구체적으로 어떻게 해결하는가?
|
||||
- 서버 사이드 렌더링(SSR) 환경에서 상태 유출을 막기 위해 Pinia가 각 요청마다 새로운 스토어 인스턴스를 생성하고 관리하는 내부 생명주기(Lifecycle) 메커니즘은 무엇인가?
|
||||
- 컴포넌트의 책임을 UI 렌더링으로만 한정하고 비즈니스 및 비동기 로직을 모두 Pinia의 Action으로 위임할 때 발생하는 컴포넌트 간 결합도 변화와 설계상의 한계는 없는가?
|
||||
- TypeScript 환경에서 Pinia의 강력한 타입 추론 기능이 대규모 Vue 3 모노레포(Monorepo) 프로젝트의 개발 생산성 및 리팩토링에 미치는 영향은 무엇인가?
|
||||
- Pinia와 Vue DevTools의 통합(타임트래블 디버깅 등)이 복잡한 상태 전이를 추적하는 데 어떻게 기술적으로 기여하는가?
|
||||
### Setup store (modern preferred)
|
||||
```ts
|
||||
// stores/counter.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** Vue 3 컴포넌트 내부에 산재된 API 호출 및 비동기 비즈니스 로직을 Pinia의 액션(Action) 계층으로 추출하여, 프론트엔드 UI 컴포넌트를 순수하게 렌더링에만 집중하는 형태로 구현합니다. [3]
|
||||
- **System Design:** 엔터프라이즈급 대규모 SPA 또는 SSR 애플리케이션 설계 시, 타입 안전성을 보장하고 보일러플레이트를 최소화하는 중앙 집중형 상태 관리 레이어로 설계에 포함합니다. [3, 4]
|
||||
- **Operation / Maintenance:** Vue DevTools와의 네이티브 통합을 통해 애플리케이션 운영 중 발생하는 복잡한 상태 변화의 타임라인을 검사하고 타임트래블 디버깅을 수행하여 유지보수를 원활하게 합니다. [1]
|
||||
- **Learning Path:** 최신 Vue 프레임워크 학습 시 Vuex를 건너뛰고, Composition API를 익힌 후 즉시 Pinia를 전역 상태 관리 표준으로 채택하여 학습하는 것이 권장됩니다. [2]
|
||||
- **My Project Relevance:** 현대적인 Vue 프론트엔드 환경에서 상태 관리의 복잡도를 낮추고 타입스크립트 기반의 안정적인 아키텍처 패턴을 구축해야 할 때 도입하는 핵심 기술로 연관됩니다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Vite]]
|
||||
- 확장 방향: Pinia와 함께 모던 Vue 애플리케이션 개발 워크플로우를 극도로 가속화하는 차세대 빌드 및 최적화 도구로 이해를 확장할 수 있습니다 [6].
|
||||
- [[React Query (TanStack Query)]]
|
||||
- 확장 방향: Vue 진영의 Pinia처럼 프론트엔드 아키텍처에서 '서버 상태(Server State)' 관리 책임을 컴포넌트로부터 분리해내는 React 생태계의 유사한 실전 패턴 도구로 비교 연구할 수 있습니다 [7].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
- Raw Source: 00_Raw/2026-05-03/Pinia.md
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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 }
|
||||
})
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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 },
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Component usage
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useCounterStore } from '@/stores/counter'
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
const store = useCounterStore()
|
||||
// 매 reactivity 매 유지: storeToRefs 매 ref 변환
|
||||
const { count, doubled } = storeToRefs(store)
|
||||
// actions 매 destructure OK (not reactive)
|
||||
const { increment } = store
|
||||
</script>
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
<template>
|
||||
<button @click="increment">{{ count }} (×2 = {{ doubled }})</button>
|
||||
</template>
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### App setup (Vue 3)
|
||||
```ts
|
||||
// main.ts
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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
|
||||
- 부모: [[Vue]] · [[State-Management]]
|
||||
- 변형: [[Vuex]] (predecessor) · [[Redux]] · [[Zustand]] · [[Jotai]]
|
||||
- 응용: [[Nuxt]] · [[Vue-SSR]]
|
||||
- Adjacent: [[Composition-API]] · [[TanStack-Query]] · [[Reactivity]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
Reference in New Issue
Block a user