Vanilla JS项目登录登出无刷新时Firestore数据重复拉取问题
问题根因
auth.onAuthStateChanged监听器的注册逻辑被放在了signInWithGoogle的登录成功回调中,每完成一次登录,就会新增一个独立的监听器实例。这类 Firebase 监听器不会随用户登出自动销毁,后续每次登录状态变更,所有已注册的监听器都会同时触发,因此登录多少次,fetchBooks就会被调用多少次。- 额外隐患:当前
fetchBooks拿到数据后直接调用addCardToHTML插入节点,没有清空已渲染的旧卡片,即使监听器问题修复,也可能出现卡片重复渲染的情况。
修复方案
方案1(推荐):全局仅注册一次鉴权监听器
将监听器逻辑从登录回调中移出,页面初始化时仅注册一次即可,修改后代码如下:
// 页面初始化阶段执行,仅注册一次鉴权状态监听 auth.onAuthStateChanged(user => { if (user) { // 拉取数据前先清空现有卡片,避免重复渲染 clearExistingBookCards() fetchBooks() } }) function signInWithGoogle(){ const provider = new firebase.auth.GoogleAuthProvider() auth.signInWithPopup(provider) .then(result => { createNewUserDocument(result.user) // 移除此处重复的onAuthStateChanged注册逻辑 }).catch(err => { console.log(err) }) signUpForm.reset() signUpModal.hide() signInForm.reset() signInModal.hide() } // 新增清空已渲染图书卡片的方法 function clearExistingBookCards() { // 假设所有图书卡片都加了统一类名book-card,根据实际业务替换选择器即可 document.querySelectorAll('.book-card').forEach(card => card.remove()) } function fetchBooks() { const docRef = db.collection('users').doc(auth.currentUser.uid).collection('books') docRef.get().then(querySnapshot =>{ console.log(querySnapshot) querySnapshot.forEach(doc => { const data = doc.data() addCardToHTML(data.title, data.author, data.pages, data.description, data.read) }) }) }
方案2(适配特殊业务场景):注册新监听器前销毁旧实例
如果你的业务逻辑确实需要在登录后才注册监听器,需要先保存上一次监听器的取消函数,注册新监听器前先销毁旧实例:
// 全局变量保存监听器取消函数 let unsubscribeAuthListener = null function signInWithGoogle(){ const provider = new firebase.auth.GoogleAuthProvider() auth.signInWithPopup(provider) .then(result => { createNewUserDocument(result.user) // 销毁之前注册的旧监听器 if (unsubscribeAuthListener) unsubscribeAuthListener() // 注册新监听器,onAuthStateChanged返回值就是取消该监听的方法 unsubscribeAuthListener = auth.onAuthStateChanged(user => { if (user) { clearExistingBookCards() fetchBooks() } }) }).catch(err => { console.log(err) }) signUpForm.reset() signUpModal.hide() signInForm.reset() signInModal.hide() }
内容的提问来源于stack exchange,提问作者Jesus Esis
相关产品推荐
相关产品推荐

