목차
Vue 기본 구조
- 기본 구조 설명 - Composition API 방식( 다른 방식으로는 Option API 방식이있음 export default{} )
 
<script setup>
// 사용하려는 store를 import
import { useTodosStore } from '@/stores/todos'
// 사용 선언
const todos = useTodosStore()
// --- state의 값을 반응형으로 참조하는 방법
const { todos, count } = storeToRefs(todos)
// --- action은 구조분해하여 사용할 수 있음.
const { increment } = todos 
// --- state의 값 수정 방법 3가지 
// 1. 값 수정
counter.count++
// 2. $patch 이용
counter.$patch({ count: counter.count + 1 })
// 3. action 이용
counter.increment()
</script>
<template>
  <!-- Store에 직접 state에 접근 -->
  <div>Current Count: {{ counter.count }}</div>
</template>
Pinia 기본 구조
- 기본 구조 설명 Option Store방식
- 기존 방식처럼 state, getters, actions를 직관적으로 표현한다.
 - stores/todos-store.js
 - 
import { defineStore } from 'pinia' export const useTodosStore = defineStore('todos', { //-- store의 이름 state: () => ({ /** @type {{ text: string, id: number, isFinished: boolean }[]} */ todos: [], /** @type {'all' | 'finished' | 'unfinished'} */ filter: 'all', // type will be automatically inferred to number nextId: 0, count: 0 }), getters: { finishedTodos(state) { return state.todos.filter((todo) => todo.isFinished) }, unfinishedTodos(state) { return state.todos.filter((todo) => !todo.isFinished) }, filteredTodos(state) { if (this.filter === 'finished') { return this.finishedTodos } else if (this.filter === 'unfinished') { return this.unfinishedTodos } return this.todos }, }, actions: { increment() { this.count++ }, addTodo(text) { this.todos.push({ text, id: this.nextId++, isFinished: false }) }, }, }) 
 
State (Vue)
- 기본적으로 인스턴스를 통해 state에 접근하여 읽고 쓸 수 있음
- 단, state에 먼저 정의가 되어있어야함.
 
const store = useStore() store.count++ 
- 초기화 (Option Store방식만 가능, Setup Store 방식은 직접 생성해야함.)
 - 
const store = useStore() store.$reset() 
- state 변경
- 직접 변경
const store = useStore() store.count++ - patch사용
const store = useStore() store.$patch({ count: store.count + 1, age: 120, name: 'DIO', })
 - array를 수정(push, remove, splice 등) 해야하는 경우라면 mutation을 그룹화 하는 함수도 가능함
const store = useStore() store.$patch((state) => { state.items.push({ name: 'shoes', quantity: 1 }) state.hasChanged = true }) 
 - 직접 변경
 - state 변경시 주의
 - 
// ❌ $state 를 대신할 수 없음 store.$state = { count: 24 } // ⭕ 내부적으로 $patch()를 호출 store.$patch({ count: 24 }) - state 변경 추적 (subscribe, 구독)
 - 
<script setup> const someStore = useSomeStore() // 이 추적은 component가 unmount된 후에도 유지됨 someStore.$subscribe(callback, { detached: true }) </script> 
State (Pinia)
- state 의 기본 구조 (Option Store 방식)
 - 
state: () => { return { // 처음에는 비어있는 list의 경우 userList: [] as UserInfo[], // 아직 load되지 않은 데이터의 경우 user: null as UserInfo | null, } }, interface UserInfo { name: string age: number } 
- State 인터페이스를 이용하는 경우 (Option Store 방식)
 - 
interface State { userList: UserInfo[] user: UserInfo | null } export const useUserStore = defineStore('user', { state: (): State => { return { userList: [], user: null, } }, }) interface UserInfo { name: string age: number } 
- state 변경 추적 (subscribe, 구독)
 - 
import { MutationType } from 'pinia' cartStore.$subscribe((mutation, state) => { mutation.type // 'direct' | 'patch object' | 'patch function' // same as cartStore.$id mutation.storeId // 'cart' // only available with mutation.type === 'patch object' mutation.payload // patch object passed to cartStore.$patch() // 변경될 때마다 전체 상태를 로컬 스토리지에 유지 localStorage.setItem('cart', JSON.stringify(state)) }) 
Getters (Vue)
- getters에 접근
 - 
<script setup> import { useCounterStore } from './counterStore' const store = useCounterStore() </script> <template> <p>Double count is {{ store.doubleCount }}</p> </template> 
- getters에 인수(argument) 전달
- computed 속성이므로 매개변수를 전달할 수는 없으나, 허용하는 방법은 있음.
 
<script setup> import { storeToRefs } from 'pinia' import { useUserListStore } from './store' const userList = useUserListStore() // <script setup> 내에서 // getUserById.value에 접근 해야함. const { getUserById } = storeToRefs(userList) </script> <template> <p>User 2: {{ **getUserById(2)** }}</p> </template>- 이 방법을 사용하면 getter는 더이상 cashed 되지 않음, 단순히 호출하는 함수
 
 
Getters (Pinia)
- vue의 computed, vuex의 getters와 유사
 - getters 의 기본 구조
 - 
export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, }), getters: { // 반환 타입을 자동으로 number로 추론함 doubleCount(state) { return state.count * 2 }, // 반환 타입은 "반드시" 명시적으로 설정해야함 doublePlusOne(): number { // 전체 store에 대한 자동 완성 및 typings ✨ return this.doubleCount + 1 }, }, }) - getters에 인수(argument) 전달
- computed 속성이므로 매개변수를 전달할 수는 없으나, 허용하는 방법은 있음.
 
export const useStore = defineStore('main', { getters: { getUserById: (state) => { return (userId) => state.users.find((user) => user.id === userId) }, }, })- 이 방법을 사용하면 getter는 더이상 cashed 되지 않음, 단순히 호출하는 함수
 
 - 다른 store의 getter 에 access
- 
import { useOtherStore } from './other-store' export const useStore = defineStore('main', { state: () => ({ // ... }), getters: { otherGetter(state) { const otherStore = useOtherStore() return state.localData + otherStore.data }, }, }) 
 - 
 
Actions (Vue)
- actions의 기본 구조
 - 
<script setup> const store = useCounterStore() // store에서 action을 호출 store.randomizeCounter() </script> <template> <button @click="store.randomizeCounter()">Randomize</button> </template> 
- action 변경 추적 (subscribe, 구독)
 - 
<script setup> const someStore = useSomeStore() // 이 구독은 component가 unmount된 후에도 유지 됨 someStore.$onAction(callback, true) </script> 
Actions (Pinia)
- actions 의 기본 구조
 - 
export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, }), actions: { // this에 의존하므로 화살표 함수 사용할 수 없음 increment() { this.count++ }, randomizeCounter() { this.count = Math.round(100 * Math.random()) }, }, }) 
- 다른 store의 actions 접근
 - 
import { useAuthStore } from './auth-store' export const useSettingsStore = defineStore('settings', { state: () => ({ preferences: null, // ... }), actions: { async fetchUserPreferences() { const auth = useAuthStore() if (auth.isAuthenticated) { this.preferences = await fetchPreferences() } else { throw new Error('User must be authenticated') } }, }, }) 
- action 변경 추적 (subscribe, 구독)
 - 
const unsubscribe = someStore.$onAction( ({ name, // action의 이름 store, // store 인스턴스(예시:someStore) args, // action에 전달되는 매개변수 배열 after, // action 반환 혹은 resolve 후의 hook onError, // action throw 혹은 rejenct 시의 hook }) => { // 특정 action 호출에 대한 공유 변수(shared variable) const startTime = Date.now() // 이 코드는 store에 대한 action 실행 전 트리거 됨 console.log(`Start "${name}" with params [${args.join(', ')}].`) // 이 코드는 action이 성공하고 완전히 실행된 후에 트리거 됨 // promised를 반환 할때까지 기다림 after((result) => { console.log( `Finished "${name}" after ${ Date.now() - startTime }ms.\nResult: ${result}.` ) }) // action throw 혹은 rejenct 시에 실행 onError((error) => { console.warn( `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.` ) }) } ) // listner를 수동으로 제거 unsubscribe() 
반응형