30. [개발] Pinia를 이용한 Vue 앱의 상태 관리 - Vue3 Firebase 프로젝트
Pinia를 이용한 Vue 앱의 상태 관리
Vue에서는 전역 상태 관리를 위해 Vuex가 널리 사용되었지만,
Vue 3에서는 Pinia가 공식적으로 추천되는 상태 관리 라이브러리가 되었습니다.
Pinia는 더 직관적이고 사용하기 쉽도록 설계되었으며,
Composition API와 완벽하게 호환됩니다.
1. Pinia란?
Pinia는 Vue 3의 상태 관리 라이브러리로, 다음과 같은 특징을 가지고 있습니다.
✅ 간단한 API → Vue의 Composition API와 자연스럽게 통합
✅ 타입스크립트 지원 → 타입스크립트 친화적
✅ 직관적인 스토어 구조 → state, getters, actions를 통해 상태 관리
✅ SSR(서버사이드 렌더링) 지원
✅ 플러그인 지원 및 확장성
2. Pinia 설치
Vite 기반의 Vue 3 프로젝트에서 Pinia를 사용하려면 다음 명령어로 설치할 수 있습니다.
npm install pinia
설치 후, main.js 에서 Pinia를 Vue 애플리케이션에 등록해야 합니다.
// main.js
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.mount("#app");
3. Pinia의 기본 구조
Pinia에서는 Store(스토어) 를 정의하여 상태(state)를 중앙에서 관리합니다.
스토어는 state, getters, actions 세 가지 핵심 개념으로 구성됩니다.
1) State (상태)
- 전역에서 관리할 데이터를 저장하는 곳
- Vue의 reactive()와 비슷한 역할을 함
2) Getters (계산된 상태)
- Vue의 computed()와 비슷하게 상태를 기반으로 계산된 값을 제공
3) Actions (비동기 로직 & 상태 변경)
- Vue의 methods와 비슷한 개념으로 상태를 변경하는 함수
- 비동기 요청(예: API 호출)도 처리 가능
4. 기본적인 Pinia Store 예제
1) Pinia Store 생성
아래는 useAuthStore라는 Pinia 스토어를 정의하는 예제입니다.
이 스토어는 사용자의 로그인 상태를 관리합니다.
// src/stores/auth.js
import { defineStore } from "pinia";
import { ref } from "vue";
import { auth, signInWithEmailAndPassword } from "@/firebase"; // Firebase Auth 예제
export const useAuthStore = defineStore("auth", () => {
const user = ref(null); // 로그인한 사용자 정보
// 로그인 함수 (Firebase 사용 예제)
const login = async (email, password) => {
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
user.value = userCredential.user;
} catch (error) {
console.error("로그인 실패:", error.message);
}
};
// 로그아웃 함수
const logout = async () => {
await auth.signOut();
user.value = null;
};
return { user, login, logout };
});
2) Pinia Store 사용하기
위에서 만든 useAuthStore를 Vue 컴포넌트에서 사용해 보겠습니다.
<template>
<div>
<p v-if="authStore.user">환영합니다, {{ authStore.user.email }}님!</p>
<v-form @submit.prevent="handleLogin">
<v-text-field v-model="email" label="Email" required></v-text-field>
<v-text-field v-model="password" label="Password" type="password" required></v-text-field>
<v-btn type="submit" color="primary">로그인</v-btn>
</v-form>
<v-btn v-if="authStore.user" @click="authStore.logout" color="red">로그아웃</v-btn>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useAuthStore } from "@/stores/auth";
const authStore = useAuthStore();
const email = ref("");
const password = ref("");
const handleLogin = () => {
authStore.login(email.value, password.value);
};
</script>
3) Getters 사용하기
getters는 computed()와 비슷한 역할을 합니다.
예를 들어, 사용자의 로그인 여부를 쉽게 확인하는 isAuthenticated getter를 추가할 수 있습니다.
// src/stores/auth.js
import { defineStore } from "pinia";
import { ref, computed } from "vue";
export const useAuthStore = defineStore("auth", () => {
const user = ref(null);
// Getter: 로그인 여부 확인
const isAuthenticated = computed(() => !!user.value);
return { user, isAuthenticated };
});
이제 Vue 컴포넌트에서 isAuthenticated를 사용할 수 있습니다.
<template>
<p v-if="authStore.isAuthenticated">로그인 상태입니다.</p>
</template>
<script setup>
import { useAuthStore } from "@/stores/auth";
const authStore = useAuthStore();
</script>
4) Actions 사용하기
actions는 methods와 같은 개념으로, 상태를 변경하는 로직을 포함합니다.
API 호출이나 비동기 처리도 가능합니다.
예를 들어, 로그인 시 Firestore에서 추가 정보를 불러오는 경우:
import { defineStore } from "pinia";
import { ref } from "vue";
import { auth, signInWithEmailAndPassword } from "@/firebase";
import { db, doc, getDoc } from "firebase/firestore";
export const useAuthStore = defineStore("auth", () => {
const user = ref(null);
const userInfo = ref(null);
// 로그인 및 Firestore에서 사용자 정보 가져오기
const login = async (email, password) => {
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
user.value = userCredential.user;
// Firestore에서 추가 사용자 정보 가져오기
const userDoc = await getDoc(doc(db, "users", user.value.uid));
if (userDoc.exists()) {
userInfo.value = userDoc.data();
}
} catch (error) {
console.error("로그인 실패:", error.message);
}
};
return { user, userInfo, login };
});
5. Pinia vs Vuex
특징PiniaVuex
API 스타일 | Composition API 기반 | Options API 기반 |
코드 복잡성 | 간결하고 직관적 | 상대적으로 복잡함 |
TypeScript 지원 | 기본 지원 | 타입 추론이 어려움 |
Mutations | 없음 (Actions로 관리) | 있음 (State 변경 시 필수) |
SSR 지원 | 기본 지원 | 추가 설정 필요 |
✅ Pinia는 Vue 3와 궁합이 잘 맞고, 더 간결하고 직관적인 API를 제공하므로 Vuex보다 사용하기 편리합니다.
결론
Pinia는 Vue 3에서 공식적으로 추천되는 상태 관리 라이브러리로,
사용이 간편하면서도 강력한 기능을 제공합니다.
- state → 전역 상태 관리
- getters → 계산된 값
- actions → 상태 변경 및 비동기 처리
✅ Pinia를 활용하면 더 직관적이고 효율적인 Vue 앱 상태 관리가 가능합니다! 🚀