如何在状态中设置Firestore onSnapshot监听器并解决取消订阅失效问题
Firestore onSnapshot 监听器取消订阅失败解决方法
问题原因
你遇到的问题由两处错误导致:
- 没有存储正确的取消订阅函数:Firestore中
onSnapshot方法的返回值才是用来终止监听的函数,你当前将前置构造的Query查询对象赋值给了this.fetchChatsListener,所以调用时会抛出「不是函数」的报错,也无法生效取消逻辑。 - 查询构造逻辑错误:Firestore的Query实例是不可变对象,每次调用
where、orderBy等方法都会返回全新的Query实例,你当前的条件判断中添加的where规则没有重新赋值给查询对象,最终生效的查询并不会包含这个过滤条件。
正确实现代码
监听器设置
// 先构造基础查询 let messageQuery = firestore() .collection('chats') .doc(documentSnapshot.id) .collection('messages') .where('created', '>=', currenttime); // 条件添加过滤规则,必须重新赋值给查询变量才能生效 if (this.state.sent_message_id !== '') { messageQuery = messageQuery.where(firebase.firestore.FieldPath.documentId(), '!=', this.state.sent_message_id); } // 添加排序规则,重新赋值 messageQuery = messageQuery.orderBy('created', 'desc'); // 调用onSnapshot,将返回的取消订阅函数存入实例属性 this.fetchChatsListener = messageQuery.onSnapshot({ error: (e) => console.error(e), next: (querySnapshot_) => { // 拷贝原state数组,避免直接突变state const newDataSource = [...this.state.dataSource]; querySnapshot_.docChanges().forEach(change => { newDataSource.push({ ...change.doc.data(), key: change.doc.id, }); }); this.setState({ chatEntered: true, dataSource: newDataSource, refreshingMessages: false, current_chat_id: documentSnapshot.id }); }, });
取消订阅逻辑
unsubscribe_chats_listener() { // 先判断是否为有效函数,避免空值调用报错 if (typeof this.fetchChatsListener === 'function') { this.fetchChatsListener(); this.fetchChatsListener = null; } }
额外提示:直接修改
this.state下的属性属于不符合React规范的操作,可能会引发渲染异常,所有state修改都应该通过setState执行。
内容的提问来源于stack exchange,提问作者showtime
相关产品推荐
相关产品推荐

