![](/img/trans.png)
[英]Nesting firestore onSnapshot listeners in react-native?
[英]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.