Files
2nd/10_Wiki/Topics/Frontend/Pinia.md
T
koriweb d8a80f6272 chore(wiki): dangling 링크 canonical 정규화 (768파일/1200건)
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해
끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은
과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업.
도구: Datacollect/scripts/link_reconcile_apply.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:24:15 +09:00

6.5 KiB
Raw Blame History

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-pinia Pinia 10_Wiki/Topics verified self
Vue Store
Pinia Store
none A 0.9 applied
vue
state-management
frontend
2026-05-10 pending
language framework
TypeScript 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)

// 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

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

<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)

// 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

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

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 감지

store.$subscribe((mutation, state) => {
  localStorage.setItem('cart', JSON.stringify(state))
}, { detached: true })

Plugin (persistedstate)

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)

// 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

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

🤖 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