0
votes

Overview/Environment:

  • a react-native project v0.61.5
  • using react-native-firebase package
  • using actions to populate redux state, display firestore data through props

Goal:

  • Listen to collection of documents
  • use Firestore's FieldValue.serverTimestamp() to set time value of a document in said collection
  • use serverTimestamp's toMillis() function inside a snapshot listener

Observations/Errors:

  • when creating a document in said collection, the document gets created fine, and displays fine
  • while the doc/time value is created, the applications crashes due to the call to doc.get('time').toMillis() which is inside the snapshot listener: TypeError: null is not an object (evaluating 'doc.get('time').toMillis()')

enter image description here

So far I've tried all the suggestions noted here: Why is Firestore's 'doc.get('time').toMillis' producing a null Type Error?

Nothing seems to resolve this crash.

here's the snapshot listener:

.onSnapshot({ includeMetadataChanges: true }, (querySnapshot) => {
    if (querySnapshot.metadata.fromCache && querySnapshot.metadata.hasPendingWrites) {
    // ignore cache snapshots where new data is being written
      return;
    }
    const messages = [];
    querySnapshot.forEach((doc) => {
        const estimateTimestamps = { serverTimestamps: 'estimate' }
        const msg = doc.data();
        msg.docId = doc.id;
        msg.time = doc.get('time', estimateTimestamps).toMillis();
        const timestamp = doc.get('time', estimateTimestamps);
        if (timestamp) {
          msg.time = timestamp.toMillis();
        } else {
          debugger
          console.error(doc.id + ' is missing "time" field!');
        }

        messages.push(msg);
    });
    dispatch({ type: types.LOAD_MSGS, payload: messages });
    resolve();
});

Here's how document is created:

const addMsg = (msg, userConvos) => {
    return firebase.firestore().collection('messages').add({
        time: firebase.firestore.FieldValue.serverTimestamp(),
        sender: msg.sender,
        read: false,
        userConvos: [userConvos.sender, userConvos.receiver],
        content: {
            type: 'msg',
            data: msg.text
        }
    });
};

I understand the value may be null fora small amount of time, I need a way to prevent the app from crashing during that period.

2

2 Answers

2
votes

The error is pointing you to this code:

doc.get('time').toMillis()

It's saying that doc.get('time') returns null, and therefore, you can't call toMillis() on that.

The answer to the question you linked to explains exactly why that is. If it's still unclear, I suggest reading it again. The timestamp will simply be null if the event that a server timestamp has not reached the server.

Perhaps you meant to check if the timestamp is null like this, without calling toMillis():

msg.isPending = doc.get('time') === null;
0
votes

After @DougStevenson helped me understand. Somewhat confusing but its important to understand the listener is constantly running, so once the Time value is available it will be set, so no real performance issues. I reformulated my approach to this, its working:

querySnapshot.forEach((doc) => {
     const estimateTimestamps = { serverTimestamps: 'estimate' }
     const msg = doc.data();
     msg.docId = doc.id;
     msg.time = doc.get('time', estimateTimestamps).toMillis();
     const timestamp = doc.get('time', estimateTimestamps)
     
     if (doc.get('time') !== null) {
       msg.time = doc.get('time').toMillis()
     }

     messages.push(msg);
 });