Firebase persistence, clear Firebase cache

You can use the snap.metadata.fromCache flag to check if the value is coming from the cache or not. Note that if the cache value and the value from the server match it won't fire your onSnapshot twice unless you add the includeMetadataChanges flag seen below, instead it would only fire it once with the metadata.fromCache flag being set to true.

db.collection('users').doc(uid).onSnapshot({ includeMetadataChanges: true }, (snap) => {
   if (!snap.metadata.fromCache) {
        const user = snap.data();
        // Code here
    }
})

[NOTE: If using Cloud Firestore instead of Realtime Database is an option for you, it has much better offline support. When you do a .get(), it will automatically attempt to fetch the latest data from the server and only use cached data if you are offline. You can also specifically request to retrieve data from either the server or cache.]

This is unfortunately expected behaviour. You can probably work around it by using observeEventOfType instead of observeSingleEventOfType

Basically, whenever you observe data, we're going to pull data from our persistent cache first. That data will be whatever data we last received from Firebase. Because you're using observeSingleEventOfType instead of observeEventOfType, you're not going to be receiving regular updates from Firebase and so the data we have cached actually won't include the latest data that you wrote.

As a simple fix, you may be able to just add an observeEventOfType on the data in question. You don't actually need to do anything with the events. But if you listen to them all the time, then your app will be getting the latest data from firebase and when you call observeSingleEventOfType, you can be confident that it'll have the latest data cached.