새발블로그
[Vue.js] Pinia로 Vue 상태 관리하기 본문
Vue 3에서는 상태 관리와 관련된 문제 해결을 위해 Pinia를 사용한다.
여러 컴포넌트에서 공통 데이터를 관리하고 공유할 수 있다.
1. Pinia란?
Pinia를 사용하면 여러 컴포넌트 간에 공통 데이터를 store로 관리하고 쉽게 공유할 수 있다. Pinia는 React와 비슷한 접근법으로 컴포넌트 단위로 데이터를 관리하며, 모듈화된 상태 관리를 지원한다.
Pinia를 사용하면 store를 정의하고, 그 안에서 state, actions, getters 등을 관리할 수 있습니다. 이로써 앱의 데이터 흐름을 한 곳에서 관리하고 쉽게 공유할 수 있다.
2. Store 생성 및 사용 방법
Pinia를 사용하려면 먼저 store를 생성해야하고, Pinia store는 defineStore 함수를 사용하여 정의한다.
store 생성 예시
src/stores/counter.js
import { defineStore } from 'pinia'
import { reactive, ref, computed } from 'vue'
export const useCount1Store = defineStore('count1', () => {
// state: 데이터 상태 관리
const state = reactive({ count: 0 })
// actions: 비즈니스 로직 (데이터를 수정하는 함수들)
const increment = (num) => {
state.count += num
}
// ref와 computed 사용 예시
const count = ref(0)
const plus = () => {
count.value++
}
// computed: 파생 데이터 (캐싱)
const test = computed(() => {
console.log('test computed 실행')
return count.value * 2
})
return { state, increment, count, plus, test }
})
- state: 앱 전체 또는 특정 기능의 데이터를 관리.
- actions: state를 수정하는 함수들입니다.
- computed: state에 의존하는 파생 데이터를 계산하고 캐싱
3. 주요 개념
| state | 앱 전체 또는 특정 기능의 데이터 상태를 관리 |
| action | 데이터 수정 또는 비즈니스 로직을 수행하는 함수 |
| getter (computed) | 파생된 데이터를 반환하는 함수입니다. 캐싱되어 성능 최적화에 도움 |
4. computed 캐싱 동작 흐름
Pinia에서 computed는 매우 중요한 역할을 한다. computed는 값이 변경되지 않으면 캐시된 값을 반환하여 성능을 최적화한다. 이 동작 흐름을 이해하는 것이 중요하다.
- 처음 호출: computed 내부의 getter 함수가 실행되어 값을 계산하고 캐싱
- 값이 변경되지 않으면: computed를 다시 호출해도 캐시된 값을 반환
- 값이 변경되면: 캐시가 삭제되고, 다시 계산하여 새로운 값을 캐시
const test = computed(() => {
console.log('test computed 실행')
return count.value * 2
})
- 위 코드에서 count 값이 변경되지 않으면 test를 여러 번 호출해도 계산을 하지 않고 캐시된 값을 반환
- count 값이 변경되면 test는 다시 계산하고 그 값을 캐싱
5. 컴포넌트에서 Pinia 사용 예시
컴포넌트에서 Pinia를 사용하려면 먼저 store를 import하고, store를 사용한다.
컴포넌트 예시
<script setup>
import { useCount1Store } from '@/stores/counter'
const countStore = useCount1Store()
function addFive() {
countStore.increment(5)
}
</script>
<template>
<div>
<p>state.count: {{ countStore.state.count }}</p>
<p>ref count: {{ countStore.count }}</p>
<p>computed test: {{ countStore.test }}</p>
<button @click="addFive">+5</button>
<button @click="countStore.plus">plus 1</button>
</div>
</template>
- useCount1Store()로 store를 가져온다.
- countStore.state.count는 state의 값을 가져온다.
- countStore.test는 computed로 정의된 파생된 데이터를 가져온다.
- increment()와 plus()는 각각 action으로 정의된 데이터 수정 함수이다.
6. Pinia와 Router, Axios 통합 예시
Axios를 통한 데이터 호출 예시
src/stores/data.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
import axios from 'axios'
export const useDataStore = defineStore('data', () => {
const data = ref(null)
const isLoading = ref(true)
const error = ref(null)
// API 호출하는 action
const fetchData = async () => {
try {
const response = await axios.get('https://api.example.com/data')
data.value = response.data
} catch (err) {
error.value = err
} finally {
isLoading.value = false
}
}
// 첫 렌더링 시 API 호출
fetchData()
return { data, isLoading, error, fetchData }
})
컴포넌트에서 API 데이터 사용
<script setup>
import { useDataStore } from '@/stores/data'
const dataStore = useDataStore()
</script>
<template>
<div v-if="dataStore.isLoading">로딩 중...</div>
<div v-if="dataStore.error">에러 발생: {{ dataStore.error }}</div>
<div v-else>
<pre>{{ dataStore.data }}</pre>
</div>
</template>
- axios를 사용하여 API에서 데이터를 받아옴
- fetchData 함수는 async로 데이터를 받아오고, isLoading과 error 상태를 관리
- 컴포넌트에서 dataStore를 통해 데이터를 표시함
Router와 함께 사용 예시
import { useRouter } from 'vue-router'
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', () => {
const router = useRouter()
const login = async (credentials) => {
try {
const response = await axios.post('/login', credentials)
if (response.data.success) {
router.push('/dashboard')
}
} catch (error) {
console.error('로그인 실패', error)
}
}
return { login }
})
'Client > Vue.js' 카테고리의 다른 글
| SPA 환경에서 이탈률(Exit/Bounce)·체류시간(Dwell)을 정확히 측정하는 방법 (0) | 2025.11.10 |
|---|---|
| D3로 값 범위(Orders-of-Magnitude)가 큰 시계열을 정확하게 시각화하는 방법 (0) | 2025.11.10 |
| [Vue.js] Vue 3에서 API 호출은 언제 하는 게 맞을까? (0) | 2025.05.04 |
| [Vue.js] Vue 생명주기 (0) | 2025.05.04 |
| [Vue.js] Composition API (0) | 2025.05.04 |