그랜파 개발자의 프론트엔드 공부-Vue

Vue로 PWA 개발, ChatGPT의 프론트엔드와 연동하여 사용할 Firestore의 예제를 실행해 봅시다.

그랜파 개발자 2024. 11. 26. 04:54

Vue로 PWA 개발 - 그랜파 개발자.

 

우리는 Firestore 예제를 통해 Firestore의 CRUD를 이해하려고 합니다.

Firestore CRUD

1. Firestore 컬렉션 접근:

  • collection(db, "todos")를 통해 todos 컬렉션에 접근.

2. 할 일 추가: Create

  • addDoc를 사용해 Firestore에 새 문서를 추가.
    const docRef = await addDoc(collection(db, "todos"), {
      title: this.newTodo.trim(),: false,
    });

3. 할 일 가져오기: Read

  • getDocs로 Firestore에서 모든 문서를 가져오기
    const querySnapshot = await getDocs(collection(db, "todos"));

4. 할 일 상태 업데이트: Update

  • updateDoc를 통해 completed 필드를 토글.
    await updateDoc(doc(db, "todos", todo.id), {
      completed: !todo.completed,
    });

5. 할 일 삭제: Delete

  • deleteDoc으로 Firestore 문서를 삭제.
    await deleteDoc(doc(db, "todos", id));

 

예제 프로젝트

1. Vue 프로젝트 만들기

vue create mylog

 

? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, PWA, Router, Vuex
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Where do you prefer placing config for Babel, ESLint, etc.?** In dedicated config files**
? Save this as a preset for future projects? (y/N) n

 

2. vuetify 설치

cd mylog

vue add vuetify

 

? Choose a preset: (Use arrow keys)
Vuetify 2 - Configure Vue CLI (advanced)
> Vuetify 2 - Vue CLI (recommended)
Vuetify 2 - Prototype (rapid development)
Vuetify 3 - Vite (preview)
Vuetify 3 - Vue CLI (preview)

 

3. firebase 설치

npm install firebase

 

4. Firebase 초기화 (firebase.js)

 

먼저 Firebase 프로젝트의 설정 정보를 추가하고 Firestore를 초기화합니다.

// src/firebase.js
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";

// Firebase 프로젝트 설정 정보
const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID",
};

// Firebase 초기화
const app = initializeApp(firebaseConfig);

// Firestore 초기화
const db = getFirestore(app);

export { db };

 

5. Vue 컴포넌트 (App.vue)

<template>
  <v-app>   

    <v-container>
      <h1>Firestore와 연동한 할 일 관리</h1>

      <!-- 새로운 할 일 추가 -->
      <v-text-field
        label="새로운 할 일을 입력하세요"
        v-model="newTodo"
        @keyup.enter="addTodo"
        outlined
      ></v-text-field>
      <v-btn color="primary" @click="addTodo">추가</v-btn>

      <!-- 할 일 목록 -->
      <v-list>
        <v-list-item
          v-for="todo in todos"
          :key="todo.id"
        >
          <v-list-item-content>
            <v-list-item-title :class="{ completed: todo.completed }">
              {{ todo.title }}
            </v-list-item-title>
          </v-list-item-content>
          <v-list-item-action>
            <v-btn
              icon
              @click="toggleComplete(todo)"
            >
              <v-icon>{{ todo.completed ? 'mdi-check-circle' : 'mdi-circle-outline' }}</v-icon>
            </v-btn>
            <v-btn
              icon
              @click="deleteTodo(todo.id)"
            >
              <v-icon color="red">mdi-delete</v-icon>
            </v-btn>
          </v-list-item-action>
        </v-list-item>
      </v-list>
    </v-container>

  </v-app>
</template>

<script>
import { db } from "@/firebase";
import {
  collection,
  addDoc,
  getDocs,
  updateDoc,
  deleteDoc,
  doc,
} from "firebase/firestore";

export default {
  name: 'App',
  data() {
    return {
      todos: [], // 할 일 목록
      newTodo: "", // 새로운 할 일 제목
    };
  },
  methods: {
    async fetchTodos() {
      try {
        const querySnapshot = await getDocs(collection(db, "todos"));
        this.todos = querySnapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));
      } catch (error) {
        console.error("Error fetching todos:", error);
      }
    },
    async addTodo() {
      if (!this.newTodo.trim()) return;
      try {
        const docRef = await addDoc(collection(db, "todos"), {
          title: this.newTodo.trim(),
          completed: false,
        });
        this.todos.push({
          id: docRef.id,
          title: this.newTodo.trim(),
          completed: false,
        });
        this.newTodo = ""; // 입력 필드 초기화
      } catch (error) {
        console.error("Error adding todo:", error);
      }
    },
    async toggleComplete(todo) {
      try {
        await updateDoc(doc(db, "todos", todo.id), {
          completed: !todo.completed,
        });
        todo.completed = !todo.completed; // 로컬 상태 업데이트
      } catch (error) {
        console.error("Error updating todo:", error);
      }
    },
    async deleteTodo(id) {
      try {
        await deleteDoc(doc(db, "todos", id));
        this.todos = this.todos.filter((todo) => todo.id !== id);
      } catch (error) {
        console.error("Error deleting todo:", error);
      }
    },
  },
  mounted() {
    this.fetchTodos(); // Firestore에서 할 일 목록 가져오기
  },
};
</script>

<style scoped>
h1 {
  margin-bottom: 16px;
}
.completed {
  text-decoration: line-through;
  color: gray;
}
</style>

 

6. 코드 설명

 

1. 할 일 가져오기

async fetchTodos() {
    try {
      const querySnapshot = await getDocs(collection(db, "todos"));
      this.todos = querySnapshot.docs.map((doc) => ({ id: doc.id,  ...doc.data()  }));
    } catch (error) {
      console.error("Error fetching todos:", error);
    }
}

 

2. 할 일 추가

async addTodo() {
  if (!this.newTodo.trim()) return;
  try {
    const docRef = await addDoc(collection(db, "todos"), {
      title: this.newTodo.trim(),: false,
    });
    this.todos.push({
      id: docRef.id, this.newTodo.trim(), false,
    });
    this.newTodo = ""; // 입력 필드 초기화
  } catch (error) {
    console.error("Error adding todo:", error);
  }
},

 

3. 할 일 수정

async toggleComplete(todo) {
  try {
    await updateDoc(doc(db, "todos", todo.id), {
      completed: !todo.completed,
    });
    todo.completed = !todo.completed; // 로컬 상태 업데이트
  } catch (error) {
    console.error("Error updating todo:", error);
  }
},

 

4. 할 일 삭제

async deleteTodo(id) {
  try {
    await deleteDoc(doc(db, "todos", id));
    this.todos = this.todos.filter((todo) => todo.id !== id);
  } catch (error) {
    console.error("Error deleting todo:", error);
  }
},

 

7. 실행

npm run serve

 

npm run serve로 로컬 서버를 시작한 후 브라우저에서 http://localhost:8080으로 이동하면 앱을 볼 수 있습니다.

 

그림 23-1

 

Vue 프로젝트 Beta Test : mylog, 일상의 기록