You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在状态中设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 20:06:01