Firestore监听场景下弹窗重复弹出问题求助(附代码)
Firestore监听仅触发一次变更,批量操作时重复弹窗问题解决
问题场景
需求:Firestore监听仅触发一次modified类型的变更。
问题:用户标记操作完成时会触发弹窗,但批量勾选多个完成项且不刷新页面时,所有之前的弹窗会持续弹出,需逐个关闭。已添加unsubscribe逻辑但问题仍存在。
相关代码:
async checkProgress(){ debugger if (this.Origin == 'SGBA') { if (this.data?.action==="update" && this.status == 'Complete') { //Gets modified document data to pass into progress popout component let newData; let q = await this.busiAssessmentService.readOverallData2(this.UID); const unsubscribe = await onSnapshot(q, (snapshot) => { let changes = snapshot.docChanges() console.log(changes.length) changes.forEach((change) => { console.log(change.type) console.log("change.type") if (change.type === "modified") { newData = change.doc.data(); console.log("Modified doc: ", change.doc.data()); this.openBox(newData, this.inputSource, this.Category) return newData; } }); },(error) => { console.log(error) }); if (newData !== undefined){ unsubscribe(); } } } }
问题分析
你的代码存在几个关键问题导致重复弹窗:
- unsubscribe时机错误:
onSnapshot的回调是异步执行的,外部判断newData !== undefined时,回调还没触发,newData仍是初始的undefined,所以unsubscribe()根本没执行,监听会一直存在,后续任何变更都会触发弹窗。 - 批量变更处理不当:批量修改时,
snapshot.docChanges()会返回多个modified类型的变更,你在forEach里每个都调用openBox,自然会弹出多个弹窗。 - 重复创建监听:每次调用
checkProgress都会新建一个Firestore监听,之前的监听没被取消,导致多个监听同时生效,批量操作时所有监听都会触发弹窗。
解决方案
修正后的代码
// 保存监听的取消函数,避免重复创建监听 let progressUnsubscribe; async checkProgress(){ // 不符合条件时,先取消已存在的监听 if (this.Origin !== 'SGBA' || this.data?.action !== "update" || this.status !== 'Complete') { if (progressUnsubscribe) { progressUnsubscribe(); progressUnsubscribe = null; } return; } // 先取消之前的监听,避免多个监听叠加 if (progressUnsubscribe) { progressUnsubscribe(); } const q = await this.busiAssessmentService.readOverallData2(this.UID); progressUnsubscribe = onSnapshot(q, (snapshot) => { // 找到第一个modified的变更 const modifiedChange = snapshot.docChanges().find(change => change.type === "modified"); if (modifiedChange) { const newData = modifiedChange.doc.data(); console.log("Modified doc: ", newData); this.openBox(newData, this.inputSource, this.Category); // 触发后立即取消监听,确保只执行一次 progressUnsubscribe(); progressUnsubscribe = null; } }, (error) => { console.log(error); // 出错时也取消监听 if (progressUnsubscribe) { progressUnsubscribe(); progressUnsubscribe = null; } }); }
关键修改点
- 全局保存取消函数:用
progressUnsubscribe变量保存监听的取消函数,每次调用checkProgress时先取消之前的监听,避免多个监听同时存在。 - 回调内立即取消监听:找到目标变更并触发弹窗后,直接在回调内部调用取消函数,确保监听只触发一次。
- 批量变更只处理一次:用
find代替forEach,只取第一个modified的变更,避免批量操作时弹出多个弹窗。 - 边界条件处理:不符合监听条件时,主动取消已存在的监听,防止无效监听残留。
内容的提问来源于stack exchange,提问作者TSH
相关产品推荐
相关产品推荐

