1

I'm watching a cloud firestore list for changes using query.onSnapshop in a react-native-firestore app, currently testing on iOS.

While my app is in the foreground, I can make data changes elsewhere (eg. in my companion web app) and the mobile app immediately updates as expected. Usually, if I make changes while the app is closed or offline, they get picked up no problem once it is re-opened or comes online again. Happy days.

However, sometimes, when the app is in the background (not closed, just some other apps have been used in the meantime), I'll make a change elsewhere (eg. add/delete a record which meets the query's criteria), then when I come back to the app, the list does not change - eg. it contains deleted records, or doesn't contain the new ones. Nothing I do on the app can change this - it remains out-of-sync, even if I make local changes, like editing one of the records (even a deleted one). Changing network conditions also does nothing (eg. switching airplane mode off/on again).

The only way the list will get back in sync is if I make another change elsewhere, while the app is still in the foreground, or if I force-close the app and re-open it again.

The issue seems to occur when connecting to both the emulator, and the actual firestore.

I don't think I'm doing anything fancy. Basically following the examples in the documentation:

import React, { useEffect, useState } from 'react';
import firestore from '@react-native-firebase/firestore';

const MyAssignments = (props) => {
  const [records, setRecords] = useState([])

  useEffect(() => {
    const onSnapshot = (snapshot) => {
       console.log(snapshot) // this IS triggered but data is stale
       setRecords(snapshot)
    }

    return firestore()
      .collection('assignments')
      .where('assignedTo', 'array-contains', props.userId)
      .onSnapshot(onSnapshot, console.error);
  }, [props.userId]);

  // render the list
  return ...
  
}

I'm not sure if this is a general firestore issue, a react-native-firebase issue, an issue with the underlying firebase ios SDK, or just my own misunderstanding?

In either case, is there a way to force the local cache to re-sync programatically, ideally when the app regains focus? Or has anyone solved a similar issue or have any ideas what to try next?

Edit 1: Note the code example above is slightly simplified for readability, as parts are spread across a few files and typed with typescript. In reality, I'm using crashlytics.recordError(e) for error handling in production, but console logging, as above, in development.

Edit 2: To debug, I've tried the following:

Switch on debug logging:

import firebase from '@react-native-firebase/app';
firebase.firestore.setLogLevel('debug');

However, this gave no extra logs in my javascript console.

I found I could view native device logs by following this guide and then filtering for Firebase, like so: idevicesyslog --match Firebase

This still shows very few logs, so I don't think debug logging is switched on properly. However, it does log this error every time I foreground the app: <Notice>: 8.9.1 - [Firebase/Firestore][I-FST000001] WatchStream (10c244d58) Stream error: 'Unavailable: Network connectivity changed'

This error happens every time though. Even when the onSnapshot successfully picks up changes

Daniel Loiterton
  • 5,073
  • 5
  • 33
  • 46
  • [`Query#onSnapshot`](https://firebase.google.com/docs/reference/js/v8/firebase.firestore.Query#onsnapshot) accepts multiple arguments or an Observable-like object to attach an error handler to it which you haven't implemented here and once a listener is errored, it gets detached and won't receive any updates. Attaching to the onError listener may give valuable info on why the listener isn't working as expected. I suspect that upon returning the app to the foreground the listener is trying to pull data before the authentication token is properly refreshed causing a silent permissions error. – samthecodingman Nov 29 '21 at 11:43
  • You can use source param in query and set it to server – Anuj Raghuvanshi Nov 29 '21 at 13:18
  • Sorry, Sam. I should have left the error handling in my simplified code example (I've updated my question). I am not rendering this component until after successful authentication, so the onSnapshot isn't run until then (and not seeing any errors). However, maybe the cache syncing still happens before authentication or something?? – Daniel Loiterton Nov 29 '21 at 13:22
  • On your last comment: synchronizing the cache happens when you attach an `onSnapshot` listener or otherwise call the API to retrieve data from Firestore. There is no background sync of any sort. --- On the original problem: it sounds like the SDK doesn't detect the restored connection, except that in that case I'd also expect it to not notice the "get back in sync is if I make another change elsewhere". It might be worth enabling debug logging to see what the SDK outputs: https://stackoverflow.com/a/52490149 – Frank van Puffelen Nov 29 '21 at 14:30
  • @DanielLoiterton did you try enabling debug logging as Frank suggested? – Farid Shumbar Nov 30 '21 at 10:46
  • Hi Frank, Farid, I've enabled debug logging, but I don't see anything in my javascript logs. Just looking into how to view native ios logs (I'm guessing that's where they go) – Daniel Loiterton Nov 30 '21 at 13:24
  • Thanks all for your help - I've updated my question with a couple of extra bits – Daniel Loiterton Nov 30 '21 at 15:46
  • Hi @DanielLoiterton, we are experiencing the same problem on iOS on certain device, the firestore does not always update. Did you solve your issue ? I tried to set the settings with `persistence: false` and `cacheSizeBytes: 0` but it didn't helped. – Dimitri Kopriwa Jun 10 '22 at 14:22
  • Hi @DimitriKopriwa, unfortunately no further progress. I think this is still a sporadic issue – Daniel Loiterton Jun 13 '22 at 10:35

0 Answers0