onSnapshot으로 데이터 변경을 실시간으로 감지하고 UI를 자동으로 갱신하는 방법을 배운다.
실시간 구독
Firestore의 가장 강력한 기능 중 하나는 실시간 동기화입니다. getDocs처럼 한 번만 읽는 대신 onSnapshot으로 구독하면, 데이터가 바뀔 때마다 콜백이 다시 호출됩니다. 채팅, 댓글, 협업 도구처럼 변화를 즉시 반영해야 하는 화면에 잘 맞습니다.
학습 목표
onSnapshot으로 문서와 컬렉션을 실시간 구독한다.- 변경 사항을 받아 UI를 자동 갱신한다.
- 구독을 올바르게 해제해 메모리 누수를 막는다.
- React 컴포넌트에서 실시간 데이터를 다룬다.
onSnapshot으로 컬렉션 구독
getDocs를 onSnapshot으로 바꾸면 됩니다. 첫 호출에서 현재 데이터를, 이후에는 변경될 때마다 새 스냅샷을 받습니다.
import { collection, query, orderBy, onSnapshot } from 'firebase/firestore';
import { db } from '@/lib/firebase';
const q = query(collection(db, 'messages'), orderBy('createdAt'));
const unsubscribe = onSnapshot(q, (snap) => {
const messages = snap.docs.map((d) => ({ id: d.id, ...d.data() }));
console.log('현재 메시지:', messages);
});
단일 문서 구독
특정 문서 하나의 변화만 듣고 싶다면 doc 참조를 넘깁니다.
import { doc, onSnapshot } from 'firebase/firestore';
import { db } from '@/lib/firebase';
const unsubscribe = onSnapshot(doc(db, 'rooms', 'room_1'), (snap) => {
if (snap.exists()) {
console.log('방 정보 갱신:', snap.data());
}
});
구독 해제
onSnapshot은 구독을 해제하는 함수를 반환합니다. 화면을 떠날 때 반드시 호출해야 불필요한 네트워크 사용과 메모리 누수를 막을 수 있습니다.
// 더 이상 듣지 않을 때
unsubscribe();
⚠️ 주의 — 구독을 해제하지 않으면 컴포넌트가 사라져도 리스너가 계속 살아남아 읽기 비용과 메모리를 낭비합니다. 구독 수만큼 해제도 반드시 짝지어야 합니다.
React에서 실시간 UI 갱신
useEffect 안에서 구독하고, 정리 함수에서 해제하는 것이 표준 패턴입니다.
import { useEffect, useState } from 'react';
import { collection, query, orderBy, onSnapshot } from 'firebase/firestore';
import { db } from '@/lib/firebase';
function useMessages() {
const [messages, setMessages] = useState<any[]>([]);
useEffect(() => {
const q = query(collection(db, 'messages'), orderBy('createdAt'));
const unsubscribe = onSnapshot(q, (snap) => {
setMessages(snap.docs.map((d) => ({ id: d.id, ...d.data() })));
});
return () => unsubscribe(); // 언마운트 시 해제
}, []);
return messages;
}
💡 TIP —
snap.docChanges()를 사용하면 추가/수정/삭제된 문서만 골라낼 수 있어, 대량 목록에서 변경분만 효율적으로 처리할 수 있습니다.
| 방식 | 특징 |
|---|---|
| getDocs | 한 번 읽고 끝 |
| onSnapshot | 변경 시마다 자동 갱신 |
요약
onSnapshot은 데이터가 바뀔 때마다 콜백을 다시 호출합니다.- 컬렉션은 쿼리 참조, 단일 문서는
doc참조를 넘겨 구독합니다. - 반환된
unsubscribe함수로 구독을 반드시 해제합니다. - React에서는
useEffect에서 구독하고 정리 함수에서 해제합니다. docChanges()로 변경된 문서만 효율적으로 처리할 수 있습니다.
연습문제
getDocs와onSnapshot의 핵심 차이는 무엇인가요?onSnapshot이 반환하는 함수는 무슨 역할을 하나요?- React에서 구독 해제를 보장하려면
useEffect에서 무엇을 반환해야 하나요? - 구독을 해제하지 않으면 어떤 문제가 생기나요?
힌트 — 리스너의 생명주기를 떠올려 보세요.
💡 연습문제 풀이
불러오는 중…
댓글 0
“Firebase” 강좌에 대한 댓글입니다.