본문 바로가기
Firebase

[Firebase] 파이어스토어 realtime update 처리하기

by 붕어사랑 티스토리 2022. 9. 23.
반응형

https://firebase.google.com/docs/firestore/query-data/listen#web-version-9

 

Cloud Firestore로 실시간 업데이트 가져오기  |  Firebase

2022년 10월 18일에 오프라인과 온라인으로 진행될 Firebase Summit에 참여하세요. Firebase로 앱을 빠르게 개발하고 안심하고 앱을 출시하며 손쉽게 확장하는 방법을 알아보세요. 지금 등록하기 의견 보

firebase.google.com

 

 

파이어스토어에 데이터가 업데이트 되었다고 하자. 당신이 이 업데이트된 내용을 실시간으로 처리하고 싶다면?

결론부터 말하자면 onSnapshot() 메소드를 이용하면 된다.

 

 

 

 

리액트에서는 아래처럼 사용한다.

import { doc, onSnapshot } from "firebase/firestore";

const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
    console.log("Current data: ", doc.data());
});

첫번째 인자에는 query 결과물이 들어가고 두번째는 callback이 들어간다.

앞으로 나올 예시에서는 doc만 나오는데 query의 결과물은 collection이 될 수도 있다.

 

 

 

Local change 이벤트

만약 당신이 데이터를 로컬에서 받아서 백엔드에 데이터를 날렸다고 치자. onSnapshot에서는 먼저 로컬 change에 대한 걸 감지하여 미리 콜백을 실행시킨다. 이렇게 하면 latency없이 미리 ui등에 반영할 수 있다.

 

허나 간혹 서버에서 불리는 콜백과, 로컬에서 불리는 콜백 이 두개를 구분해야 할 경우가 있다.

metadata.hasPendingWrites을 이용해 local에서 불린 콜백인지, 서버에서 불린 콜백인지 구분하는 방법을 제공한다.

import { doc, onSnapshot } from "firebase/firestore";

const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
  const source = doc.metadata.hasPendingWrites ? "Local" : "Server";
  console.log(source, " data: ", doc.data());
});

 

 

 

 

Metadata 변화 감지하기

위 예시를 보고 한가지 의문점이 드실 겁니다.

 

"어라 그럼 내가 보낸 데이터가 서버에 기록 되었을 때를 알고 싶으면 어떡하지?"

 

이를 위해 onSnapshot 메소드는 이러한 케이스에 대해 여러가지 옵션 파라미터들을 전달 할 수 있는데요. 여기서 옵션파라미터에 includeMetadataChanges 값에 true를 주면 메타데이터가 변할 때 도 콜백을 호출 할 수 있습니다.

 

import { doc, onSnapshot } from "firebase/firestore";

const unsub = onSnapshot(
  doc(db, "cities", "SF"), 
  { includeMetadataChanges: true }, 
  (doc) => {
    // ...
  });

아래 예시를 보시죠

 

1. 로컬에서 서버에 데이터를 보냅니다. 이때 메타데이터의 pending writes 값은 true입니다.

2. 서버에서 데이터를 write합니다

3. 서버에서 클라이언트에게 데이터가 write 되었음을 알립니다. 이때 데이터는 변화가 없지만, 메타데이터의 pending writes 값은 false가 되어 전달됩니다.

 

즉 3번 케이스에서 메타데이터가 변경되었으므로 onSnapshot 콜백은 한번 더 불리게 됩니다.

 

 

사실 위 예시에서 데이터가 업데이트를 되는 케이스만 언급했지만 다른 메타데이터도 변할 때마다 매번 콜백이 호출됩니다. 다른건 필요없고 데이터만 업데이트 되었는지 아닌지 알고 싶으시다면 데이터를 추가할 때 아래처럼 then 메소드로 콜백을 붙이시는걸 추천합니다.

addDoc(collection(db,"docs"),{
  ...
  ...
  }).then{
  //콜백작성
  });

 

 

 

 

여러개의 doc에 대한 업데이트 알림 받기

아래처럼 쿼리를 이용해 여러개의 docs를 받은 후 onSnapshot을 적용할 수 도 있습니다.

import { collection, query, where, onSnapshot } from "firebase/firestore";

const q = query(collection(db, "cities"), where("state", "==", "CA"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
  const cities = [];
  querySnapshot.forEach((doc) => {
      cities.push(doc.data().name);
  });
  console.log("Current cities in CA: ", cities.join(", "));
});

 

 

 

변화에 대한 종류 감지하기

아래처럼 change를 이용하면, 데이터의 변화가 추가, 업데이트, 삭제 이 셋중 어느것인지 구분 할 수 있습니다.

 

import { collection, query, where, onSnapshot } from "firebase/firestore";

const q = query(collection(db, "cities"), where("state", "==", "CA"));
const unsubscribe = onSnapshot(q, (snapshot) => {
  snapshot.docChanges().forEach((change) => {
    if (change.type === "added") {
        console.log("New city: ", change.doc.data());
    }
    if (change.type === "modified") {
        console.log("Modified city: ", change.doc.data());
    }
    if (change.type === "removed") {
        console.log("Removed city: ", change.doc.data());
    }
  });
});

 

 

 

 

리스너 제거하기

onSnapshot이 자기 자신을 stop하는 메소드를 리턴합니다. 더이상 db 업데이트에 대한 알림을 받고 싶지 않다면 아래처럼 리스너를 제거 할 수 있습니다.

import { collection, onSnapshot } from "firebase/firestore";

const unsubscribe = onSnapshot(collection(db, "cities"), () => {
  // Respond to data
  // ...
});

// Later ...

// Stop listening to changes
unsubscribe();

 

 

 

리스너 에러 처리하기

간혹가다가 리스너에 에러가 생길 수 있습니다. 예를들면 쿼리한 데이터에 퍼미션이라던지 또는 잘못된 쿼리를 listen하려 하였을 때가 있습니다. 이러한 에러를 예외처리 하고 싶다면 아래처럼 error 콜백을 달아 줄 수 있습니다.

import { collection, onSnapshot } from "firebase/firestore";

const unsubscribe = onSnapshot(
  collection(db, "cities"), 
  (snapshot) => {
    // ...
  },
  (error) => {
    // ...
  });
반응형

댓글