Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
343 views
in Technique[技术] by (71.8m points)

javascript - Displaying firestore timestamp gets error when using onSnapshot() on react-native

I am creating a chat app using firestore where I use Flatlist and querying using onSnapshot() to show both sender and receiver realtime

my sample query below is like this:

const ChatMessages = useCallback(() => {
 privateMessage
  .doc(chatId)
  .collection('messages')
  .orderBy('createdAt', 'asc')
  .onSnapshot((querySnapshot) => {
    const messageList = [];
    querySnapshot.forEach((doc) => {
      messageList.push(doc.data());
    })
    setMessages(messageList);
  }, error => {
    console.log(error)
  })
 }, [chatId])

then in my sample flatlist I have the user display name, message, and the time created that will be displayed on the screen:

<FlatList
  data={messages}
  keyExtractor={(item, index) => String(index)}
  removeClippedSubviews={false}
  renderItem={({ item }) => (

   <View>

      <Text style={chatstyle.pmdate}>
        {item.createdAt.toDate().toDateString()}
      </Text>

      <Text>
        {item.displayName}
      </Text>

      <Text>
        {item.message}
      </Text>

   </View>
  )}
/>

I would like to display the time and date but when using onSnapshot() I get null is not an object (evaluating 'item.createdAt.toDate') error but when I removed {item.createdAt.toDate().toDateString()} everything is ok. I tried the get() query and the timestamp works fine but of course it's not realtime.

What is the right way to display the timestamp using onSnapshot()?

question from:https://stackoverflow.com/questions/66057189/displaying-firestore-timestamp-gets-error-when-using-onsnapshot-on-react-nativ

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your problem comes from the "latency compensation": "Local writes in your app will invoke snapshot listeners immediately. ... When you perform a write, your listeners will be notified with the new data before the data is sent to the backend". See the doc on onSnapshot().

Since you use firebase.firestore.FieldValue.serverTimestamp() to set the value of createdAt (which is a good approach), the value of createdAt is calculated by the backend (the serverTimestamp sentinel is replaced by a server-generated timestamp in the written data).

Therefore, at the moment the snapshot listener is invoked in your front-end following the local write ("Local writes in your app will invoke snapshot listeners immediately"), this value is not set (item.createdAt.toDate() generates an error).

One solution is to use the metadata.hasPendingWrites property that indicates whether the document has local changes that haven't been written to the backend yet.

For example:

const ChatMessages = useCallback(() => {
 privateMessage
  .doc(chatId)
  .collection('messages')
  .orderBy('createdAt', 'asc')
  .onSnapshot((querySnapshot) => {
    const messageList = [];
    querySnapshot.forEach((doc) => {
      messageList.push(doc.data());
    })
    if (!querySnapshot.metadata.hasPendingWrites) {  // <======
       setMessages(messageList);
    }

  }, error => {
    console.log(error)
  })
 }, [chatId])

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...