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으로 이동하면 앱을 볼 수 있습니다.
Vue 프로젝트 Beta Test : mylog, 일상의 기록
'그랜파 개발자의 프론트엔드 공부-Vue' 카테고리의 다른 글
Vue로 PWA 개발, ChatGPT가 시키는 대로 프론트엔드 UI를 만들었습니다. (0) | 2024.11.28 |
---|---|
Vue로 PWA 개발, ChatGPT에게 프론트엔드 앱을 위한 UI를 물었습니다. (0) | 2024.11.27 |
Vue로 PWA 개발, ChatGPT에게 프론트엔드와 연동하는 Firestore의 예제를 요청했습니다. (0) | 2024.11.25 |
Vue로 PWA 개발, ChatGPT에게 프론트엔드 개발을 위한 서버리스 백엔드 Firebase를 물었습니다. (0) | 2024.11.24 |
Vue로 PWA 개발, ChatGPT의 프론트엔드 앱 Vuetify 예제를 실행해 봅시다. (1) | 2024.11.23 |