Vue 3 + Firebase 기반 실시간 채팅 앱 개발
10. Vue 3 + Firebase 기반 실시간 채팅 앱 v-chat 개발 - 새채팅
그랜파 개발자
2025. 5. 8. 22:32
새채팅
새로운 채팅을 하려면 채팅 상대의 메일 주소를 알아야 합니다.
‘새채팅’ 페이지에서 상대의 메일 주소를 입력하고 채팅 시작 버튼을 누르면 새로운 채팅을 시작할 수 있습니다.
채팅방으로 이동할 때 상대의 Id, 이름, 채팅방 Id를 query로 채팅방에 전달합니다.
새채팅방 만들기
새 채팅방을 만들기 위해서는 나와 상대의 userId가 필요합니다.
상대의 userId는 입력한 상대의 이메일로 상대의 userId를 구합니다.
나의 userId와 상대의 userId로 채팅방을 찾아 있으면 채팅방 Id를 가져오고
채팅방이 없으면 새로운 채팅방을 만들고 채팅방으로 이동합니다.
chatRooms 컬렉션의 구조
chatRooms/
{chatRoomId}/
userIds: [user1Id, user2Id]
createdAt: timestamp
messages/
{messageId}/
이메일로 userId 가져오기 - authStore
const getUidByEmail = async (email) => {
const profileRef = collection(db, 'profiles');
const q = query(profileRef, where('email', '==', email));
const snapshot = await getDocs(q);
if (snapshot.empty) return null;
// 첫 번째 사용자 가져오기
const profile = snapshot.docs[0].data();
const uids = profile.uids;
// 첫 번째 uid 반환 (또는 원한다면 모든 uid를 고려할 수도 있음)
return uids?.[0] || null;
}
새 채팅방 만들기 - chatStore
const findOrCreateChatRoom = async (currentUserId, otherUserId) => {
const chatRoomsRef = collection(db, 'chatRooms');
const q = query(chatRoomsRef, where('userIds', 'array-contains', currentUserId));
const snapshot = await getDocs(q);
// 같은 유저 조합이 있는지 확인
for (const doc of snapshot.docs) {
const userIds = doc.data().userIds;
if (userIds.includes(otherUserId)) {
return doc.id; // 기존 채팅방 ID 반환
}
}
// 없으면 새로 생성
const newRoomRef = await addDoc(chatRoomsRef, {
userIds: [currentUserId, otherUserId],
createdAt: Timestamp.now(),
});
return newRoomRef.id;
};
StartChat.vue
<!-- src/views/StartChat.vue -->
<template>
<v-container fluid>
<v-row align="center" justify="center">
<v-col cols="12" sm="10" md="6">
<v-card elevation="10" class="pa-4">
<v-card-title>새 채팅 시작</v-card-title>
<v-text-field
v-model="otherEmail"
label="상대 이메일"
outlined
dense
type="email"
:rules="emailRules"
/>
<v-btn color="primary" block class="mt-2" @click="startChat">
채팅 시작
</v-btn>
<v-alert v-if="error" type="error" class="mt-2" dense>{{ error }}</v-alert>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script setup>
import { ref } from 'vue';
import { useAuthStore } from '@/stores/authStore';
import { useChatStore } from '@/stores/chatStore';
import { useRouter } from 'vue-router';
const auth = useAuthStore();
const chat = useChatStore();
const router = useRouter();
const otherEmail = ref('');
const error = ref('');
const emailRules = [
(v) => !!v || '이메일을 입력해주세요.',
(v) => /.+@.+\..+/.test(v) || '올바른 이메일 형식이 아닙니다.',
];
const startChat = async () => {
error.value = '';
// 이메일로 상대 uid 구하기
const otherUid = await auth.getUidByEmail(otherEmail.value.trim());
if (!otherUid) {
error.value = '입력한 이메일을 가진 사용자를 찾을 수 없습니다.';
return;
}
if (otherUid === auth.user.uid) {
error.value = '자기 자신과는 채팅할 수 없습니다.';
return;
}
// 상대 uid로 프로필을 찾기
const foundProfile = auth.profiles.find(p => p.id === otherUid);
//const foundProfile = auth.profiles.find(p => p.uids.includes(otherUid));
// 상대 uid로 채팅방 찾기
const chatRoomId = await chat.findOrCreateChatRoom(auth.user.uid, otherUid);
// 채팅방으로 이동
router.push({ path: '/chat', query: {
otherUserId: foundProfile.id,
otherUserName: foundProfile.name,
roomId: chatRoomId
}});
};
</script>
Vue Router에서 query와 params
Vue Router에서 query와 params는 URL을 통해 데이터를 전달하는 두 가지 주요 방법입니다.
각각의 차이점과 사용 방법은 다음과 같습니다:
✅ params: 동적 라우트 매개변수
- 라우트 경로에 직접 포함되는 값
- 보통 /user/:id, /chat/:roomId처럼 URL 경로의 일부로 사용됨
🔹 사용 예시
// 라우터 정의
{
path: '/user/:id',
name: 'User',
component: UserView
}
// 이동
router.push({ name: 'User', params: { id: '123' } })
// 결과: /user/123
// 컴포넌트 내에서 사용
const route = useRoute();
console.log(route.params.id); // "123"
✅ query: 쿼리 문자열 (URL 끝 ? 뒤에 붙는 값)
- ? 뒤에 붙는 키-값 쌍
- URL에 여러 필터, 페이지 정보 등 가볍게 전달할 때 사용
🔹 사용 예시
// 이동
router.push({ path: '/search', query: { keyword: 'hello', page: 2 } })
// 결과: /search?keyword=hello&page=2
// 컴포넌트 내에서 사용
const route = useRoute();
console.log(route.query.keyword); // "hello"
console.log(route.query.page); // "2"
📌 차이점 요약
구분 | params | query |
URL 위치 | 경로의 일부 (/user/:id) | URL 끝 (?page=2) |
라우트 정의 필요 | ✅ 필요 (:id) | ❌ 불필요 |
주 용도 | 리소스 ID, 상세 페이지 | 검색, 필터, 정렬 등 옵션 |
예시 URL | /user/123 | /search?keyword=hello |
원하는 목적에 따라 선택하면 됩니다:
- 고유 식별자 → params
- 옵션, 필터, 설정값 → query