【问题标题】:Displaying firestore timestamp gets error when using onSnapshot() on react-native在 react-native 上使用 onSnapshot() 时显示 Firestore 时间戳会出错
【发布时间】:2021-05-09 10:27:52
【问题描述】:

我正在使用 Firestore 创建一个聊天应用程序,我使用 Flatlist 并使用 onSnapshot() 进行查询以实时显示发送者和接收者

我下面的示例查询是这样的:

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])

然后在我的示例平面列表中,我有将显示在屏幕上的用户显示名称、消息和创建的时间:

<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>
  )}
/>

我想显示时间和日期,但是在使用 onSnapshot() 时我得到 null is not an object (evalating 'item.createdAt.toDate') 错误但是当我删除 {item.createdAt.toDate().toDateString ()} 一切都好。我尝试了 get() 查询,时间戳工作正常,但它当然不是实时的。

使用 onSnapshot() 显示时间戳的正确方法是什么?

【问题讨论】:

  • 您能展示一下您是如何创建消息文档的吗?
  • 我只是用 firebaseMessage.doc(id).set(userMessages).catch(e => {console.log(e))} 发送消息
  • 我使用的是 const newDate = firebase.firestore.FieldValue.serverTimestamp() 这个在使用 onSnapshot() 显示日期时不能直接工作

标签: javascript firebase react-native google-cloud-firestore


【解决方案1】:

您的问题来自“延迟补偿”:“您的应用程序中的本地写入将立即调用快照侦听器。...当您执行写入时,您的侦听器将在数据发送到之前收到新数据的通知后端”。请参阅onSnapshot() 上的doc

由于你使用firebase.firestore.FieldValue.serverTimestamp()来设置createdAt的值(这是一个好办法),createdAt的值由后端计算serverTimestamp的sentinel是替换为写入数据中的服务器生成的时间戳)。

因此,在本地写入之后在您的前端调用快照侦听器的那一刻(“您的应用中的本地写入将立即调用快照侦听器”),此值未设置item.createdAt.toDate() 生成错误)。

一种解决方案是使用metadata.hasPendingWrites 属性来指示文档是否具有尚未写入后端的本地更改。

例如:

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])

【讨论】:

    【解决方案2】:

    我也是 React 的新手,但是对于那些正在寻找快速解决方案并且无法找到解决方法的人来说,这里有一个:

    const ChatMessages = useCallback(() => {
     privateMessage
      .doc(chatId)
      .collection('messages')
      .orderBy('createdAt', 'asc')
      .onSnapshot((querySnapshot) => {
        const messageList = [];
        querySnapshot.forEach((doc) => {
         if(querySnapshot.createdAt) // Here is the magic Line of Code
          messageList.push(doc.data());
        })
        setMessages(messageList);
      }, error => {
        console.log(error)
      })
     }, [chatId])
    

    是的,就是这样。一个 if 语句检查数据中的 createdAt 属性,然后只将数据推送到您的数组。

    如果您正在考虑此解决方案的缺点,那么就是这样:

    if() 验证的时间在您的程序中是额外的。

    PS:我在我的 react 应用程序上尝试了当前批准的解决方案,但仍然发生 timeStamp 上的 null 问题。

    【讨论】:

    • 感谢您给我另一个想法。
    猜你喜欢
    • 2020-04-04
    • 2018-10-22
    • 2019-06-21
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多