FirebaseError: Quota exceeded:如何正确关闭Firebase的snapShot监听器
问题根因
- 你的代码未处理组件提前卸载的场景:如果组件在1秒的定时器触发前就被卸载,
unsubscribe方法永远不会执行,监听器会持续在后台运行,持续产生读请求消耗配额 - React 开发环境默认开启严格模式(StrictMode)时,组件会执行两次挂载逻辑,相当于单次页面加载就会创建2个独立的监听器,开发过程中频繁热重载更新代码的话,泄漏的监听器会快速堆叠,很快耗尽免费配额
- 即使你主动调用了
unsubscribe,onSnapshot在绑定成功的瞬间就会触发一次全量读取,如果你页面切换频繁,每次进入都触发一次全量读取,也会快速累加读请求次数
修复方案
- 补全useEffect的清空逻辑,不管定时器有没有触发,组件卸载时都直接关闭监听器,同时清空定时器避免内存泄漏,修改后的代码如下:
useEffect(() => { console.log("Loading snapShots on firebase"); const unsubscribe = db.collection('chats').onSnapshot(snapshot => ( setChats(snapshot.docs.map(doc => ({ id: doc.id, data: doc.data() }))) )) const timer = setTimeout(()=>{ unsubscribe(); }, 1000); // 新增组件卸载时的清空逻辑 return () => { clearTimeout(timer) unsubscribe() } }, [])
- 如果你的业务场景不需要实时更新聊天数据,只需要进入页面拉取一次,直接替换
onSnapshot为单次get请求,完全不需要处理监听器逻辑,消耗的配额只有单次读取:
useEffect(() => { const getChats = async () => { console.log("Loading chats from firebase"); const snapshot = await db.collection('chats').get(); setChats(snapshot.docs.map(doc => ({ id: doc.id, data: doc.data() }))) } getChats() }, [])
- 开发阶段可以暂时关闭React严格模式,避免重复挂载产生多余的监听器和读请求
- 登陆Firebase控制台,进入Firestore的使用统计页面,查看具体的读请求消耗明细,确认是否有其他未关闭的监听器在持续产生请求
内容的提问来源于stack exchange,提问作者Tercé Nicolas
相关产品推荐
相关产品推荐

