繁体   English   中英

在 react-native 上使用 onSnapshot() 时,显示 firestore 时间戳会出错

[英]Displaying firestore timestamp gets error when using onSnapshot() on react-native

我正在使用 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 (evaluating 'item.createdAt.toDate') 错误但是当我删除 {item.createdAt.toDate().toDateString()}一切都好。 我尝试了 get() 查询,时间戳工作正常,但当然不是实时的。

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

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

由于您使用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])

我也是 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 问题仍然发生。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM