프로필이미지가 다 똑같이 나오는 이슈가 발생..!
이를 해결하기 위해서 다음과 같이 해결하였습니다.
[ Firebase를 사용하여 채팅 메시지를 표시하는 컴포넌트 ]
import { useState, useEffect } from 'react';
import { useRecoilValue } from 'recoil';
import classNames from 'classnames';
import classes from './Message.module.scss';
import { authImagState } from '@/@recoil/authImgState';
import defaultAvatar from '/public/assets/defaultAvatars.svg';
import { collection, doc, getDoc, onSnapshot } from '@firebase/firestore';
import { db } from '@/firebase/app';
import { auth } from '@/firebase/auth';
interface MessageProps {
message: {
text: string;
photoURL: string;
uid: string;
};
}
export function Message({ message }: MessageProps) {
const [photoURL, setPhotoURL] = useState<string>(defaultAvatar);
//authImagState는 현재 로그인한 사용자의 프로필 이미지
const imageUrl = useRecoilValue(authImagState);
useEffect(() => {
if (!message.uid) {
return;
}
const docRef = doc(collection(db, 'users'), message.uid);
//해당 데이터를 필요로 하지 않는 경우, unsubscribe()를 호출하여 해당 데이터의 수신을 중단
let unsubscribe: (() => void) | undefined;
async function getUserDoc() {
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const userData = docSnap.data();
setPhotoURL(userData.photoURL || defaultAvatar);
}
}
getUserDoc().then(() => {
unsubscribe = onSnapshot(docRef, (docSnap) => {
const userData = docSnap.data();
if (userData?.photoURL) {
setPhotoURL(userData.photoURL);
}
});
});
return () => {
if (unsubscribe) {
unsubscribe();
}
};
}, [message.uid]);
// 현재 메시지의 프로필 이미지 URL을 반환
function getImageUrl() {
if (imageUrl) {
return isCurrentUser() ? imageUrl : photoURL;
}
return photoURL;
}
// 현재 사용자가 메시지 작성자인지 확인
function isCurrentUser() {
return auth.currentUser?.uid === message.uid;
}
return (
<div className={classNames(classes.message, classes.owner)}>
<div className={classes.messageInfo}>
<img
src={getImageUrl()}
alt={
isCurrentUser()
? '로그인된 사용자의 프로필 이미지'
: '메시지를 작성한 사용자의 프로필 이미지'
}
/>
</div>
<div className={classes.messageContent}>
{message.photoURL && <img src={message.photoURL} alt={'채팅 이미지'} />}
<p>{message.text}</p>
</div>
</div>
);
}
useEffect(() => {
if (!message.uid) {
return;
}
const docRef = doc(collection(db, 'users'), message.uid);
//해당 데이터를 필요로 하지 않는 경우, unsubscribe()를 호출하여 해당 데이터의 수신을 중단
let unsubscribe: (() => void) | undefined;
async function getUserDoc() {
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const userData = docSnap.data();
setPhotoURL(userData.photoURL || defaultAvatar);
}
}
getUserDoc().then(() => {
unsubscribe = onSnapshot(docRef, (docSnap) => {
const userData = docSnap.data();
if (userData?.photoURL) {
setPhotoURL(userData.photoURL);
}
});
});
return () => {
if (unsubscribe) {
unsubscribe();
}
};
}, [message.uid]);
위 코드는 useEffect 훅을 사용하여 Firebase Firestore의 onSnapshot 메서드를 이용하여 메시지 작성자의 프로필 이미지 URL을 가져오고, 상태를 업데이트합니다.
해당 코드에서 useEffect 훅은 message.uid 값이 변경될 때마다 호출됩니다. 이를 통해 메시지 작성자의 UID가 있을 경우, 해당 사용자의 문서 참조를 가져옵니다. docRef는 Firestore의 doc 함수를 사용하여 해당 참조를 만들고, collection 함수를 사용하여 users 컬렉션에서 문서를 가져옵니다.
getUserDoc 함수는 getDoc 함수를 사용하여 해당 문서의 스냅샷을 가져오고, userData 객체에서 photoURL 속성 값을 가져옵니다. 이후, setPhotoURL 함수를 사용하여 상태를 업데이트합니다.
onSnapshot 메서드는 Firebase Firestore에서 문서에 대한 변경 사항을 실시간으로 수신하도록 구독하는 메서드입니다. 이를 통해 사용자가 프로필 이미지를 변경하면 해당 변경 사항을 실시간으로 수신하고, setPhotoURL 함수를 사용하여 상태를 업데이트합니다.
마지막으로, return 구문에서는 unsubscribe 함수를 반환합니다. 이 함수는 구독을 취소하기 위해 사용됩니다. unsubscribe 함수는 onSnapshot 함수가 반환하는 객체에서 호출할 수 있으며, 구독을 취소하여 문서 변경 사항을 더 이상 수신하지 않도록 할 수 있습니다.
🌼 결과
참고.
https://firebase.google.com/docs/firestore/query-data/listen?hl=ko
'Project' 카테고리의 다른 글
채팅 구현시 카카오로 로그인 된 정보값을 가져오지 못하는 문제 (0) | 2023.04.09 |
---|---|
채팅 구현시 구글 로그인된 정보값을 가져오지 못하는 문제 (0) | 2023.04.09 |
React에서 페이지 변경 시 카드 딜레이 구현하기 (0) | 2023.04.02 |
접근성을 고려하여 Tab 키 만을 이용해서 작동 구현 (0) | 2023.04.01 |
채팅 기능 메세지와 이미지 업로드 구현 (0) | 2023.03.24 |