🤔 파이어스토어와 실시간 데이터베이스의 차이점이 뭐야?
대표적으로는 사용하는 쿼리가 다르다는 것!
그리고 사용 용도에 따라 조금 더 유리한 쪽이 있고 더 불리한 쪽이 있다고 한다.
사실 이런 채팅에 더 유리한 것은 실시간 데이터베이스라서 실시간 데이터베이스를 먼저 시도해봤지만.... 안 되는데 어쩌겠어. 되는 거 해야지.
파이어스토어 프로젝트 설정 하단에 가면 주는 내용이다.
env파일에 키를 정의해 두고 process.env로 가져와서 사용하자.
😤 참고로 말입니다
nextJS에서 env파일의 값을 사용하려면 앞에 꼭 NEXT PUBLIC 을 붙여줘야 한다!
const firebaseConfig = {
apiKey: `${process.env.NEXT_PUBLIC_FIREBASE_APIKEY}`,
authDomain: `${process.env.NEXT_PUBLIC_FIREBASE_AUTHDOMAIN}`,
databaseURL: `${process.env.NEXT_PUBLIC_FIREABASE_DATABASEURL}`,
projectId: `${process.env.NEXT_PUBLIC_FIREBASE_PROJECTID}`,
storageBucket: `${process.env.NEXT_PUBLIC_FIREABASE_STORAGEBUCKET}`,
messagingSenderId: `${process.env.NEXT_PUBLIC_FIREBASE_MESSAGINGSENDERID}`,
appId: `${process.env.NEXT_PUBLIC_FIREBASE_APIID}`,
};
//먼저 설정되어 있는 파이어베이스가 있는지 확인한 후 APP정의.
const app = getApps().length ? getApp() : initializeApp(firebaseConfig);
export { app };
😡 config에서 app만 선언해 주세요!
다른 사람들이 쓴 이전 버전 파이어스토어에서는 getFirestore(app)까지 정의해준 후 해당 getFirestore를 export했는데, 버전 업데이트 이후에는 이렇게 하면 정의된 app을 못 찾아서 에러가 발생한다!
app만 export 해주고 getFirestore는 사용 장소에서 정의해 주자!
이유를 몰라서 하루종일 삽질했던 부분. 에러를 잘 읽자..
😎 스냅샷이란?
사용자의 콜백이 최초로 호출될 때 단일 문서의 현재 콘텐츠로 문서 스냅샷이 생성된다.
이 스냅샷 서버는 리스너와 관련된 변경 사항을 능동적으로 모니터링한다!
모니터링하던 콘텐츠가 변경될 때마다 콜백이 호출되어 문서 스냅샷을 업데이트한 후, 해당 업데이트를 로컬 데이터와 병합한다.
👉 그러니까, DB계의 useQuery같은 녀석이라는 것!
기본적인 원리는 소켓 채팅과 비슷하다! 받고 뿌리고 받고 뿌리고..
const firestore = getFirestore(app);
const chatRef = useRef<HTMLInputElement>(null);
const scrollMobileRef = useRef<HTMLDivElement>(null);
const profile = useRecoilValue(myProfileAtom);
const [chatHistory, setChatHistory] = useState<ChatType[]>(chats);
const [loading, setLoading] = useState<boolean>(false);
//반복해서 사용할 필요 없이, 처음에 한 번만 정의해 주면 알아서 작동한다!
const Snapshot = onSnapshot(
query(
collection(firestore, `lunchbus/${id}/messages`),
orderBy("order", "desc")
),
snapshot => {
//ui를 업데이트하기 위해 state에 넣어줬다.
setChatHistory(makeData(snapshot));
},
);
//이건 항상 채팅방 맨 아래 스크롤을 유지하도록 하기 위한 덤.
useEffect(() => {
scrollMobileRef.current.scrollTop = scrollMobileRef.current.scrollHeight;
}, [chatHistory]);
const chatSubmit = async () => {
if (chatRef.current.value == "") return;
setLoading(true);
//useQuery가 아니라서 loading을 수동으로 적용해야 함...
const sendMessage = {
name: profile.name,
text: chatRef.current.value,
order:
chatHistory.length == 0
? 0
: chatHistory[chatHistory.length - 1].order + 1,
};
//firestore의 모든 함수는 비동기!
await addDoc(collection(firestore, `lunchbus/${id}/messages`), sendMessage);
chatRef.current.value = "";
setLoading(false);
};
const keyPress = async e => {
//참고로, keyDown이나 keyUp은 한글 입력시 중복 submit되는 오류가 있다!
if (e.key === "Enter") await chatSubmit();
};
DB가 쌓이면 쌓일수록 채팅이 느려진다..
소켓과 달리 약간의 딜레이가 존재한다.
그만 버전 업데이트를 해!!
웹소켓이 아니라 파이어스토어를 선택한 이유는, 현재 프로젝트 상황에서 파이어스토어의 장점이 더 유리하게 작용할 것이라고 생각했기 때문.
채팅을 작용하고자 하는 런치버스는 채팅방 생성과 삭제가 빈번하여 데이터가 많이 쌓이지 않는 가벼운 채팅을 필요로 했고, 프로젝트 스케줄과 우선순위상 채팅에 많은 에너지와 시간을 쏟을 수 없는 상황이었기 때문에 파이어스토어를 선택했다.
만약 해당 프로젝트에서 채팅이 큰 비중을 차지하거나 통신이 오래 지속되는 채팅, 0.1초 단위의 버퍼링도 허용하지 않는 리얼타임 채팅을 필요로 했다면 웹소켓을 채용했을 것이다.