Firebase v8 updateProfile()更新数据需重登、重复建文档问题
问题描述
- 尝试将
score变量存储到Cloud Firestore对应用户的highscore字段时,数据变更只有重新通过Google账号登录才会显示 - 即便使用同一个Google账号登录,每次登录都会生成新的用户文档
- 更新
displayName这类Firebase Auth标准字段可以正常生效,但自定义的highscore字段始终无法更新,重新登录、调用reload()方法重载用户数据都无效 - 使用技术栈:原生Vanilla JS + Firebase Web v8命名空间版本
原问题中实现代码如下:
function gameOver () { if (score > highscore) { GAME_OVER_TEXT.innerText = 'New Highscore:'; HIGHSCORE.innerText = `${score} points.`; STARS.classList.remove('hide'); SPARKLE.classList.remove('hide'); const user = firebase.auth().currentUser; user.updateProfile({ highscore: score }).then(() => { console.log('Update successful'); }).catch((error) => { console.log('Update unsuccessful' + error); }); user.currentUser.reload(); } else { GAME_OVER_TEXT.innerText = 'Your score:'; HIGHSCORE.innerText = `${score} points.`; } }
问题原因
你的代码存在三个核心逻辑错误:
updateProfile()是Firebase Auth的内置方法,仅支持更新Auth系统预设的两个用户属性:displayName和photoURL,传入自定义的highscore字段时,该方法会直接忽略自定义参数,不会做任何存储处理,更不会自动把数据同步到Cloud Firestore。- 代码写法存在语法和时序问题:
currentUser是firebase.auth()实例的属性,不是已获取到的user对象的属性,user.currentUser.reload()本身就是无效调用;同时你把reload()写在了updateProfile的异步回调外面,没有等更新操作执行完成就调用重载,就算是合法的内置属性更新也拿不到最新值。 - 每次登录创建新文档、数据不同步的本质原因:你没有编写任何向Firestore写入自定义字段的逻辑,且之前存用户数据时没有用用户唯一标识
uid作为文档ID,才会导致重复生成文档。
修正方案
- 自定义用户业务数据(比如
highscore)不要存在Auth用户Profile中,统一存储到Cloud Firestore的用户集合下,固定用用户的uid作为文档ID,从根源上保证同一账号永远对应同一个文档,不会重复创建。 - 修正异步逻辑,写入操作完成后再更新本地状态,Firestore存储的业务数据不需要调用
reload()方法,直接读写Firestore文档即可。
修正后的可运行代码(适配Firebase v8):
// 提前初始化Firestore实例,确保页面已经引入Firestore相关SDK const db = firebase.firestore(); function gameOver () { if (score > highscore) { GAME_OVER_TEXT.innerText = 'New Highscore:'; HIGHSCORE.innerText = `${score} points.`; STARS.classList.remove('hide'); SPARKLE.classList.remove('hide'); const user = firebase.auth().currentUser; // 未登录状态兜底 if (!user) { console.log('用户未登录,无法保存高分'); return; } // 以用户uid为文档ID写入数据,merge:true表示增量更新,不覆盖文档已有字段 db.collection('users').doc(user.uid).set({ highscore: score, // 可同步存储Auth内置字段,减少后续查询次数 lastLoginTime: new Date() }, { merge: true }) .then(() => { console.log('高分更新成功'); // 写入成功后再更新本地highscore变量,保证本地和云端数据一致 highscore = score; }) .catch((error) => { console.log('高分更新失败:', error); }); } else { GAME_OVER_TEXT.innerText = 'Your score:'; HIGHSCORE.innerText = `${score} points.`; } }
后续读取逻辑说明
需要获取用户高分时,直接读取对应Firestore文档即可:
// 用户登录成功后拉取用户保存的高分 firebase.auth().onAuthStateChanged(user => { if (user) { db.collection('users').doc(user.uid).get().then(doc => { if (doc.exists) { const userData = doc.data(); highscore = userData.highscore || 0; } }) } })
注意:如果需要给Auth用户配置全局自定义属性(比如用户权限标识),无法通过前端
updateProfile方法写入,必须通过Firebase Admin SDK在服务端设置,前端没有直接写入权限。
内容的提问来源于stack exchange,提问作者noKeyboardsLeftToSmash
相关产品推荐
相关产品推荐

