Cloud Firestore synchronization & offline cache

Cloud Firestore synchronization & offline cache

How to take advantage of Cloud Firestore's cache to develop great user experiences.

In Firestore systems, we don't wait for the server's responses when writing. We write and let the cache behind the system handle it.

How it works

Cloud Firestore from a high-level perspective uses a cache that sits between the app and the server. This allows i.e. the app to still work when there is no internet connection.

The cool thing with this is how we don't need to wait for the server's responses in order to show the user the data, we can optimistically show it after modifying documents, and in the background, the cache will eventually talk to the server and make sure the write happens there.

In more technical terms, Cloud Firestore uses IndexedDB under the hood as its cache.

Let me demonstrate with a visual how this sort of works.

Screenshot from 2022-09-20 08-40-57.png

onSnapshot

onSnapshot(postDoc, (snapshot) => {
  const post = snapshot.data();
  console.log(post);
  // First time: { text: "First Text" }
  // Second time: { text: "Second Text" }
});

updateDoc(postDoc, { text: "Second Text" });

The first data returned from onSnapshot will be coming from the server, the second time, Firestore will create a pending write, and write to the cache, so everything happens offline first making the UI really snappy. It assumes things will go well, if it doesn't, then it will roll back.

Document change types

The docChanges array can list what type of changes has happened since we started listening for the data.

The types of changes that could happen are "added", "removed", and "modified", the document itself, and the old and new indexes of the array position. This makes it easier to deal with UI that changes styles as things get added, removed or modified.

onSnapshot(postsCollection, snapshot => {
  console.log(snapshot.docChanges[0]);
  // { type: 'added', doc: {}, oldIndex: -1, newIndex: 1 }
});

addDoc(postsCollection, { text: 'Hey, this is some text' });

Metadata

The snapshot also comes with metadata that lets you see whether the data you received is from the cache and whether the write operation is still pending (hasn't been updated in the server yet).

onSnapshot(postDoc, (snapshot) => {
  console.log(snapshot.data());
  // First time: { text: "First Text" }
  // Second time: { text: "Second Text" }

  console.log(snapshot.metadata);
  // First time: { fromCache: false, hasPendingWrite: false }

  // Second time (data is updated locally): { fromCache: true, hasPendingWrite: true }
});

updateDoc(postDoc, { text: "Second Text" });

Conclusion

One of the neat things with Cloud Firestore is how it has the ability to work offline and will abstract away the hard work for you.