如何监听Firebase UI Auth的DisplayName更新并同步至Firestore?
解决方案
1. 替换Riverpod监听流:从authStateChanges()到userChanges()
authStateChanges()仅监听用户登录/登出状态,不会触发用户资料(如DisplayName)的变更通知。改用Firebase Auth提供的userChanges()流,它会监听用户所有信息的变动(包括DisplayName、邮箱、头像等)。
用Riverpod的StreamProvider封装这个流:
final authUserProvider = StreamProvider<User?>((ref) { return FirebaseAuth.instance.userChanges(); });
之后在UI中监听这个Provider,就能获取到DisplayName更新后的用户对象。
2. 同步更新Firestore用户文档
有两种可靠的实现方式:
方式一:在流监听中自动同步
通过map操作处理userChanges()的输出,当DisplayName发生实际变更时,更新Firestore文档,同时避免重复写入:
final authUserProvider = StreamProvider<User?>((ref) { // 用StateProvider缓存上一次的DisplayName,避免重复更新Firestore final prevDisplayName = ref.watch(_prevDisplayNameProvider); final userStream = FirebaseAuth.instance.userChanges(); return userStream.map((user) { if (user != null && user.displayName != prevDisplayName) { FirebaseFirestore.instance.collection('users').doc(user.uid).update({ 'displayName': user.displayName, 'updatedAt': FieldValue.serverTimestamp(), }); // 更新缓存的DisplayName ref.read(_prevDisplayNameProvider.notifier).state = user.displayName; } return user; }); }); // 私有StateProvider,用于缓存上一次的DisplayName final _prevDisplayNameProvider = StateProvider<String?>((ref) => null);
方式二:利用ProfileScreen的保存回调手动同步
firebase_ui_auth的ProfileScreen提供了onProfileSaved回调,用户点击保存按钮后会触发,直接在这里更新Firestore更高效:
ProfileScreen( providerConfigs: [EmailAuthProvider()], // 用户保存资料时触发 onProfileSaved: (updatedUser) { FirebaseFirestore.instance.collection('users').doc(updatedUser.uid).update({ 'displayName': updatedUser.displayName, 'updatedAt': FieldValue.serverTimestamp(), }); }, );
3. 获取实际变更内容
通过缓存上一次的用户信息,对比新的用户对象即可拿到变更前后的内容:
// 在Widget中监听authUserProvider final currentUser = ref.watch(authUserProvider).value; final prevUser = ref.watch(_prevUserProvider); // 对比DisplayName的变化 if (currentUser != null && prevUser != null && currentUser.displayName != prevUser.displayName) { print('DisplayName变更:${prevUser.displayName} → ${currentUser.displayName}'); } // 监听用户变化,更新缓存的上一次用户信息 ref.listen(authUserProvider, (_, next) { if (next.value != null) { ref.read(_prevUserProvider.notifier).state = next.value; } }); // 私有StateProvider,缓存上一次的用户对象 final _prevUserProvider = StateProvider<User?>((ref) => null);
内容的提问来源于stack exchange,提问作者Zach Russell
相关产品推荐
相关产品推荐

