Flutter中如何本地更新Firestore数据?优化点赞操作性能
本地更新Firestore点赞字段实现方案
初始数据拉取代码
late List<QueryDocumentSnapshot> _allData; late List<QueryDocumentSnapshot> _filteredData; void fetchData() async { QuerySnapshot querySnapshot = await FirebaseFirestore.instance .collection('games') .orderBy('likes', descending: true) .get(); _allData = querySnapshot.docs; _filteredData = _allData; setState(() { _isLoading = false; }); }
问题场景
用户对单条文档执行点赞/取消点赞操作后,若重新全量拉取数据效率过低,需在本地直接更新likes计数与likedby用户数组,同时同步更新Firestore数据库。
已完成的基础代码
void updateLike(String gameId, bool liked, String userId) { print(gameId); print(liked); print(userId); int gameIndex = _allData.indexWhere((doc) => doc.id == gameId); }
完整本地更新实现
void updateLike(String gameId, bool liked, String userId) { // 找到目标文档在_allData中的索引 int gameIndex = _allData.indexWhere((doc) => doc.id == gameId); if (gameIndex == -1) return; // 未找到对应文档,直接返回 // 将不可变的文档数据转为可修改的Map Map<String, dynamic> updatedData = Map.from(_allData[gameIndex].data() as Map<String, dynamic>); if (liked) { // 处理点赞逻辑:计数+1,添加用户ID到点赞列表 updatedData['likes'] = (updatedData['likes'] ?? 0) + 1; List<String> likedByList = List.from(updatedData['likedby'] ?? []); if (!likedByList.contains(userId)) { likedByList.add(userId); updatedData['likedby'] = likedByList; } } else { // 处理取消点赞逻辑:计数-1,移除用户ID updatedData['likes'] = (updatedData['likes'] ?? 0) - 1; List<String> likedByList = List.from(updatedData['likedby'] ?? []); likedByList.remove(userId); updatedData['likedby'] = likedByList; } // 用copyWith创建新的QueryDocumentSnapshot实例替换原数据(原对象不可变) _allData[gameIndex] = _allData[gameIndex].copyWith(data: updatedData); // 同步更新过滤后的列表(如果过滤列表包含该文档) int filteredIndex = _filteredData.indexWhere((doc) => doc.id == gameId); if (filteredIndex != -1) { _filteredData[filteredIndex] = _allData[gameIndex]; } // 更新UI setState(() {}); // 异步更新Firestore数据库 FirebaseFirestore.instance.collection('games').doc(gameId).update({ 'likes': updatedData['likes'], 'likedby': updatedData['likedby'], }); }
关键说明
QueryDocumentSnapshot是不可变对象,必须通过copyWith方法生成新实例来修改数据- 处理字段时要兼容初始值为
null的情况,避免空指针异常 - 同步更新
_filteredData,保证过滤后的列表数据与源数据一致 - UI更新与数据库更新分离,先更新本地UI提升用户体验,再异步同步到云端
内容的提问来源于stack exchange,提问作者Sprowk
相关产品推荐
相关产品推荐

