Javascript 为什么Firestore';s';doc.get(';time';).toMillis';是否生成空类型错误?
在react本机应用程序中,我调用一个动作,将数据发送到firebase。但是在调用之后,我得到一个错误,其来源似乎与快照侦听器的工作方式有关。添加消息操作大致如下所示: 创建数据:Javascript 为什么Firestore';s';doc.get(';time';).toMillis';是否生成空类型错误?,javascript,firebase,react-native,redux,react-redux,Javascript,Firebase,React Native,Redux,React Redux,在react本机应用程序中,我调用一个动作,将数据发送到firebase。但是在调用之后,我得到一个错误,其来源似乎与快照侦听器的工作方式有关。添加消息操作大致如下所示: 创建数据: const addMsg = (msg, convoIds) => { console.log('Firestore Write: (actions/conversation) => addMsg()'); return firebase.firestore().collection(
const addMsg = (msg, convoIds) => {
console.log('Firestore Write: (actions/conversation) => addMsg()');
return firebase.firestore().collection('messages').add({
time: firebase.firestore.FieldValue.serverTimestamp(),
sender: msg.sender,
receiverToken: msg.receiverToken,
sessionId: msg.sessionId,
read: false,
charged: false,
userConvos: [ convoIds.sender, convoIds.receiver ],
content: {
type: 'msg',
data: msg.text
}
});
};
我还有一个快照侦听器(在componentDidMount中执行),它用firestore中的集合中的消息填充redux存储。快照侦听器如下所示:
export const getMessages = (convoId) => {
const tmp = convoId == null ? '' : convoId;
return (dispatch) => {
console.log('Firestore Read (Listener): (actions/conversation) => getMessages()');
return new Promise((resolve, reject) => {
firebase
.firestore()
.collection('messages')
.where('userConvos', 'array-contains', tmp)
.orderBy('time')
.onSnapshot((querySnapshot) => {
const messages = [];
querySnapshot.forEach((doc) => {
const msg = doc.data();
msg.docId = doc.id;
msg.time = doc.get('time').toMillis();
messages.push(msg);
});
dispatch({ type: types.LOAD_MSGS, payload: messages });
resolve();
});
});
};
};
在同一屏幕组件中填充平面列表的相应缩减器,如下所示:
const INITIAL_STATE = {
messages: []
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case types.LOAD_MSGS:
return {
messages: action.payload
};
default:
return { ...state };
}
};
问题:一旦数据发送,我立即得到一个错误TypeError:null不是一个对象(评估'doc.get('time')).toMillis'
。如果我重新加载应用程序,导航回相关屏幕,会显示消息,时间数据也会显示。因此,我猜firebase调用的约定性质中出现了延迟,延迟会导致时间值初始化为空,但其长到足以使应用程序崩溃
问题:这里的幕后到底发生了什么?我如何防止此错误?您遇到的问题是由
onSnapshot()引起的
侦听器在一个小窗口期间从本地Firestore缓存触发,其中的值被认为是挂起的,默认情况下被视为null
。一旦服务器接受您的更改,它将使用时间戳的所有新值进行响应,并再次触发您的onSnapshot()
侦听器
如果不小心,这可能会导致你的应用程序“闪烁”,因为它会将数据打印两次
要更改挂起的时间戳的行为,可以将对象作为最后一个参数传递给和(视情况而定)
以下代码指示Firebase SDK根据本地时钟估计新的时间戳值
const estimateTimestamps={
服务器时间戳:“估计”
}
querySnapshot.forEach((doc)=>{
const msg=doc.data();//此处msg.time=null
msg.docId=doc.id;
msg.time=doc.get('time',estimateTimestamps).toMillis();//更新msg.time以设置值(或估计值,如果不可用)
消息推送(msg);
});
如果要显示消息仍在写入数据库,可以在估计时间戳之前检查msg.time
是否为null
const estimateTimestamps={
服务器时间戳:“估计”
}
querySnapshot.forEach((doc)=>{
const msg=doc.data();//挂起时此处msg.time=null
msg.docId=doc.id;
msg.isPending=msg.time==null;
msg.time=doc.get('time',estimateTimestamps).toMillis();//更新msg.time以设置值(或估计值,如果不可用)
消息推送(msg);
});
如果您希望忽略这些中间“本地”事件而等待服务器的完整响应,您可以使用:
.onSnapshot({includeMetadataChanges:true},(querySnapshot)=>{
if(querySnapshot.metadata.fromCache&&querySnapshot.metadata.hasPendingWrites){
return;//忽略正在写入新数据的缓存快照
}
常量消息=[];
querySnapshot.forEach((doc)=>{
const msg=doc.data();
msg.docId=doc.id;
msg.time=doc.get('time',estimateTimestamps).toMillis();
消息推送(msg);
});
分派({type:types.LOAD_MSGS,payload:messages});
解决();
});
在上面的代码块中,请注意,我在忽略事件之前也进行了检查,这样当您第一次加载应用程序时,它会立即打印出所有缓存的信息。如果不这样做,您将显示一个空消息列表,直到服务器响应。大多数站点将打印出所有缓存的数据,同时在页面顶部显示一个跳动器,直到服务器会以任何新数据进行响应。doc.get('time')null吗?@LajosArpad当我在屏幕组件中访问它时,它会显示时间如果我是你,我会在
msg.time=doc.get('time').toMillis()行之前;
以console.log(doc.get('time').toMillis()的形式做一个实验)
。您将看到这是否为空。这是您解决问题所需的关键信息。@LajosArpad已经有了。所有时间都是get-loggedCan您可以添加一个关于您遇到问题的确切错误消息的逐字引用吗?作为补充说明,别忘了正确处理您的侦听器toonSnapshot()
返回一个取消订阅函数,当您的组件被释放时,您应该存储并调用该函数。例如,const UnsbMessageListener=firebase…onSnapshot(…);
和当被释放时调用UnsbMessageListener()
。非常有见地的信息。但是在尝试列出的所有三个选项后,我仍然遇到相同的错误,听起来像是您的集合中的一个或多个文档缺少时间
字段/将其设置为空值,这可能是由于将消息
数组中的一个条目保存回数据库而没有t正确的时间戳(因此,msg.time
现在应该是null
),例如在编辑消息时。请尝试此操作,而不是msg.time=…
行:constamp timestamp=doc.get('time',estimateTimestamps);if(timestamp){msg.time=timestamp.toMillis();}else{console.error(doc id+'缺少“time”字段!');/*debugger;*/}
。如果遇到问题,请取消注释debugger;
并仔细查看。是的,执行了else条件,但当我检查相关文档时,“时间”字段在那里?我将奖励赏金,因为您是唯一花时间帮助的人,尽管我尚未修复错误:'(