Nuxt3中如何正确解绑Firestore onSnapshot监听器
Nuxt3 中 Firestore
onSnapshot 监听器正确解绑方案 错误原因
你的代码解绑失败的核心问题是:onSnapshot 调用后返回的是一个可执行的解绑函数,你在onUnmounted钩子里仅引用了unsubscribe.value,并没有主动调用这个函数,所以监听器始终没有被销毁,页面卸载后依然会持续触发回调输出日志,长期运行还会造成内存泄漏。
另外你的代码还存在两个隐性bug:
- 新增文档时没有存储文档
id,会导致后续修改、删除操作时findIndex永远匹配不到对应项 - 导入了未使用的
getDocs方法,属于冗余代码 onMounted加了不必要的async标记,内部没有任何await异步操作
修正步骤
- 在
onUnmounted钩子中主动执行解绑函数,执行前增加类型判断避免空值报错 - 移除冗余的
async标记和未使用的导入 - 文档数据写入响应式变量时补充
id字段 - 修正
loading状态逻辑:初始化默认loading = true,监听器首次返回数据后再置为false
修正后完整代码
<script setup> import { useUserStore } from '@/stores/user' import { onSnapshot, collection, query, where } from 'firebase/firestore' const userStore = useUserStore() const loading = ref(true) const userPosts = reactive([]) const unsubscribe = ref(null) onMounted(() => { const { firestore } = useFirebase() const userPostsRef = collection(firestore, 'posts') const q = query(userPostsRef, where('uid', '==', userStore.userProfile.uid)) unsubscribe.value = onSnapshot(q, (snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === 'added') { console.log('added', change.doc.data()) userPosts.push({...change.doc.data(), id: change.doc.id}) } if (change.type === 'modified') { console.log('modified', change.doc.data()) const updateIndex = userPosts.findIndex((post) => post.id === change.doc.id) if (updateIndex > -1) { userPosts.splice(updateIndex, 1, {...change.doc.data(), id: change.doc.id}) } } if (change.type === 'removed') { console.log('removed', change.doc.data()) const removeIndex = userPosts.findIndex((post) => post.id === change.doc.id) if (removeIndex > -1) { userPosts.splice(removeIndex, 1) } } }) loading.value = false }) }) onUnmounted(() => { // 主动调用解绑函数 if (typeof unsubscribe.value === 'function') { unsubscribe.value() unsubscribe.value = null } }) </script>
额外注意事项
- 如果你的查询依赖的
uid是动态变化的,记得在变更查询条件前先调用旧的unsubscribe方法销毁旧监听器,避免同时存在多个活跃监听器 - 如果你使用了Nuxt的
<KeepAlive>缓存页面,需要把解绑逻辑移到onDeactivated钩子中,绑定逻辑对应放到onActivated里,避免缓存页面的监听器被提前销毁
内容的提问来源于stack exchange,提问作者redshift
相关产品推荐
相关产品推荐

