로그인 후에는 마이로그의 댓글에 대해 답글을 쓸 수 있습니다. 댓글의 답글에 대한 댓글을 쓰는 것은 지원하지 않습니다. 마이로그는 마이로그, 댓글, 답글의 구조를 가지고 있습니다. 물론 하나의 마이로그에 대해 여러 댓글이 가능하고, 하나의 댓글에 대해 여러 답글은 가능합니다.
ChatGPT에게 물었습니다.
댓글에 대한 답글을 쓰고 싶어.
ChatGPT
댓글에 대한 답글 기능을 구현하려면, 댓글마다 답글(reply)을 저장하고 관리해야 합니다. 이를 위해 Firestore에서는 각 댓글마다 하위 컬렉션으로 답글을 저장하는 방식으로 설계할 수 있습니다. 댓글의 하위 컬렉션에 답글을 추가하고, 댓글과 함께 답글을 화면에 표시하도록 Vue.js에서 구현하는 방법을 설명하겠습니다.
1. Firestore에서 답글 구조 설계
Firestore의 댓글마다 하위 컬렉션으로 답글을 저장하는 구조를 사용할 수 있습니다. 기본적으로 Firestore에서 게시물(Post) -> 댓글(Comment) -> 답글(Reply) 구조로 데이터를 관리하게 됩니다.
Firestore 구조 예시:
- posts (컬렉션)
- postId (문서)
- comments (하위 컬렉션)
- commentId (문서)
- content: "This is a comment"
- author: "User123"
- createdAt: serverTimestamp()
- replies (하위 컬렉션)
- replyId (문서)
- content: "This is a reply"
- author: "User456"
- createdAt: serverTimestamp()
- comments (하위 컬렉션)
2. Vuex에서 답글 저장 및 불러오기
Vuex에서 댓글과 유사하게 답글도 Firestore에 저장하고 관리할 수 있습니다. 각각의 댓글(commentId)에 대해 하위 컬렉션으로 답글을 추가하거나 가져오는 방식입니다.
Vuex Store (store.js)
import { getFirestore, collection, addDoc, serverTimestamp, query, orderBy, getDocs } from "firebase/firestore";
const db = getFirestore();
const store = new Vuex.Store({
state: {
comments: [], // 댓글 목록
},
mutations: {
setComments(state, comments) {
state.comments = comments;
},
addComment(state, comment) {
state.comments.push(comment);
},
addReply(state, { commentId, reply }) {
const comment = state.comments.find(c => c.id === commentId);
if (comment) {
if (!comment.replies) {
comment.replies = [];
}
comment.replies.push(reply);
}
},
},
actions: {
// 댓글 불러오기
async fetchComments({ commit }, postId) {
try {
const q = query(collection(db, "posts", postId, "comments"), orderBy("createdAt", "asc"));
const querySnapshot = await getDocs(q);
const comments = [];
querySnapshot.forEach((doc) => {
comments.push({ id: doc.id, ...doc.data(), replies: [] });
});
commit('setComments', comments);
} catch (error) {
console.error("댓글 가져오기 실패:", error);
}
},
// 댓글에 답글 추가
async addReply({ commit }, { postId, commentId, content, author }) {
try {
const replyRef = await addDoc(collection(db, "posts", postId, "comments", commentId, "replies"), {
content: content,
author: author,
createdAt: serverTimestamp(),
});
const newReply = { id: replyRef.id, content, author, createdAt: new Date() };
commit('addReply', { commentId, reply: newReply });
} catch (error) {
console.error("답글 추가 실패:", error);
}
},
// 특정 댓글의 답글 불러오기
async fetchReplies({ commit }, { postId, commentId }) {
try {
const q = query(collection(db, "posts", postId, "comments", commentId, "replies"), orderBy("createdAt", "asc"));
const querySnapshot = await getDocs(q);
const replies = [];
querySnapshot.forEach((doc) => {
replies.push({ id: doc.id, ...doc.data() });
});
replies.forEach(reply => {
commit('addReply', { commentId, reply });
});
} catch (error) {
console.error("답글 불러오기 실패:", error);
}
},
},
});
export default store;
3. Vue 컴포넌트에서 답글 기능 구현
댓글 및 답글 화면 (PostComments.vue)
<template>
<div>
<h3>Comments</h3>
<!-- 댓글 목록 -->
<ul v-if="comments.length > 0">
<li v-for="comment in comments" :key="comment.id">
<strong>{{ comment.author }}</strong>: {{ comment.content }}
<ul v-if="comment.replies && comment.replies.length > 0">
<li v-for="reply in comment.replies" :key="reply.id">
<strong>{{ reply.author }}</strong>: {{ reply.content }}
</li>
</ul>
<!-- 답글 작성 폼 -->
<div>
<input v-model="newReplies[comment.id]" placeholder="Write a reply..." />
<button @click="submitReply(comment.id)">Reply</button>
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
postId: {
type: String,
required: true,
},
},
data() {
return {
newReplies: {}, // 댓글별 답글 입력 값
};
},
computed: {
comments() {
return this.$store.state.comments;
},
},
methods: {
async submitReply(commentId) {
const author = "Anonymous"; // 여기서 사용자 정보를 가져올 수 있음
const content = this.newReplies[commentId];
if (content && content.trim()) {
await this.$store.dispatch('addReply', {
postId: this.postId,
commentId: commentId,
content: content,
author: author,
});
this.newReplies[commentId] = ''; // 입력 필드 초기화
}
},
},
mounted() {
// 컴포넌트가 로드되면 해당 게시물의 댓글을 불러옴
this.$store.dispatch('fetchComments', this.postId);
},
};
</script>
4. 설명
- 댓글 목록: fetchComments를 통해 Firestore에서 댓글을 가져와 화면에 표시합니다. 댓글과 댓글에 대한 답글도 함께 보여줍니다.
- 답글 입력 폼: 각 댓글마다 답글을 입력할 수 있는 폼이 있습니다. 답글을 입력하면 submitReply 메서드를 통해 Vuex의 addReply 액션을 호출하고, Firestore에 저장합니다.
- 답글 가져오기: 답글이 있으면 comment.replies 배열을 사용해 해당 댓글 아래에 답글을 표시합니다.
5. 답글 수정 및 삭제 기능 추가
답글 수정 기능
import { updateDoc, doc } from "firebase/firestore";
async updateReply({ postId, commentId, replyId, newContent }) {
const replyRef = doc(db, "posts", postId, "comments", commentId, "replies", replyId);
try {
await updateDoc(replyRef, {
content: newContent,
updatedAt: serverTimestamp(),
});
console.log("답글이 수정되었습니다.");
} catch (error) {
console.error("답글 수정 실패:", error);
}
}
답글 삭제 기능
import { deleteDoc, doc } from "firebase/firestore";
async deleteReply({ postId, commentId, replyId }) {
const replyRef = doc(db, "posts", postId, "comments", commentId, "replies", replyId);
try {
await deleteDoc(replyRef);
console.log("답글이 삭제되었습니다.");
} catch (error) {
console.error("답글 삭제 실패:", error);
}
}
요약
댓글마다 답글 기능을 추가하기 위해 하위 컬렉션을 사용해 Firestore에 데이터를 저장하고 불러올 수 있습니다. Vuex의 actions를 통해 댓글의 하위 컬렉션에 답글을 추가하고, 상태 관리로 댓글과 답글을 화면에 반영합니다. 추가로 답글 수정 및 삭제 기능을 구현하여 답글에 대한 기능을 확장할 수 있습니다. 이 구조를 사용하면 댓글에 대한 답글을 Firestore에서 관리하며, 실시간으로 UI에 반영할 수 있습니다.
'Vue로 PWA 개발' 카테고리의 다른 글
35. mylog 찾기 (0) | 2024.10.28 |
---|---|
34. mylog 답글 구현 (0) | 2024.10.26 |
32. mylog 댓글 쓰기 구현 (0) | 2024.10.26 |
31. mylog 댓글 쓰기 (0) | 2024.10.26 |
30. mylog 수정, 내 마이로그 보기 구현 (0) | 2024.10.25 |