Vue3, Firebase 프로젝트 - 채팅앱 VSignal

30. [개발] Pinia를 이용한 Vue 앱의 상태 관리 - Vue3 Firebase 프로젝트

그랜파 개발자 2025. 4. 13. 04:41

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 앱 상태 관리가 가능합니다! 🚀