Flutter使用Bloc跨页面传值分步保存用户资料避免数据丢失
核心原因
Amplify DataStore的save操作为全量覆盖更新,第二页提交时使用的User实例未携带第一页已更新的字段,导致原有字段被空值覆盖。具体有两个直接诱因:
- 第一页保存数据后未更新自身state内的user字段,跳转时传给第二页的是初始旧User实例
- 第二页直接基于旧User实例新增description字段后提交,缺失第一页更新的name、city、avatarKey等字段,提交后这些字段被清空
解决方案
方案1:修复状态与传参逻辑(最快修复)
第一步:修改第一页ProfileBloc的保存逻辑
第一页SaveProfileChanges事件中保存完新用户数据后,需要同步更新state内的user字段:
// 第一页SaveProfileChanges事件的try块内 await dataRepo.updateUser(updatedUser2); print(updatedUser2); yield state.copyWith( formStatus: SubmissionSuccess(), user: updatedUser2, // 新增这行,更新state内的user为最新值 );
第二步:跳转第二页时传入最新的User实例
第一页提交成功跳转第二页时,取state里已经更新的user传给第二页,第二页初始化Profile2Bloc时直接使用这个传入的最新user,不要用全局缓存的初始旧user。
方案2:修改数据仓库更新逻辑(兜底防覆盖)
从根源避免全量更新导致的字段覆盖问题,把updateUser改成增量合并更新,每次更新前先查库内最新数据再合并字段:
Future<User> updateUser(User updatedUser) async { try { // 先查询库内最新的用户数据 final existingUsers = await Amplify.DataStore.query( User.classType, where: User.ID.eq(updatedUser.id), ); if (existingUsers.isEmpty) throw Exception("未找到对应用户"); final latestUser = existingUsers.first; // 合并字段:新值非空就用新值,否则保留旧值 final mergedUser = latestUser.copyWith( name: updatedUser.name ?? latestUser.name, city: updatedUser.city ?? latestUser.city, avatarKey: updatedUser.avatarKey ?? latestUser.avatarKey, description: updatedUser.description ?? latestUser.description, // User模型的其他字段都按上述规则补充即可 ); await Amplify.DataStore.save(mergedUser); return mergedUser; } catch (e) { rethrow; } }
改完之后就算传入的User实例缺字段,也不会覆盖已经存在的旧值。
可选优化:第二页初始化时主动拉取最新数据
如果担心传参不可靠,可以在Profile2Bloc初始化时主动从数据库拉取最新用户数据,替换传入的user:
Profile2Bloc( {User? user, required bool isCurrentUser, required this.dataRepo}) : super(Profile2State(user: user, isCurrentUser: isCurrentUser)) { // 初始化时拉取最新用户数据 dataRepo.getUserById(user!.id).then((latestUser) { // 抛事件更新state内的user为最新值 add(Profile2UserUpdated(latestUser: latestUser)); }); }
注:需要自行补充Profile2UserUpdated事件和对应的mapEventToState处理逻辑,以及DataRepository的getUserById查询方法。
内容的提问来源于stack exchange,提问作者azeter09
相关产品推荐
相关产品推荐

