Flutter中使用Change Notifier Provider更新数据的正确方式
在Flutter中使用ChangeNotifier Provider更新Firestore食谱列表的正确方式
先看你提供的RecipeProvider代码,核心疑问是addRecipe方法里两种更新本地列表的方式哪种更合理,以下是具体分析和最优方案:
两种现有方式的优劣
1. 重新拉取完整列表(当前做法)
recipes = await _recipeService.getUserRecipes(); notifyListeners();
- 优势:绝对保证本地数据与Firestore完全同步,不管服务器端有没有额外字段处理(比如自动生成ID、时间戳),或者是否有其他客户端修改了数据,拉取的列表都是最新的。
- 劣势:额外发起全量网络请求,当列表条目较多时,会增加带宽消耗和等待时间,拖慢UI更新速度。
2. 直接本地添加新食谱(注释的代码)
//recipes.add(newRecipe);
- 优势:无额外网络请求,UI即时更新,用户体验流畅。
- 劣势:如果Firestore的
addRecipe操作会对传入的newRecipe做修改(比如自动生成文档ID、补充服务器端字段),本地添加的对象会和服务器实际存储的不一致;另外如果有其他设备/客户端修改了该用户的食谱列表,本地数据会出现不同步的情况。
推荐的正确做法
根据你的Firestore服务实现,分两种场景选择最优方案:
场景一:addRecipe返回服务器保存后的完整对象
如果你的RecipeService.addRecipe方法可以返回Firestore中实际存储的RecipeModel(包含所有服务器生成的字段),优先采用本地添加返回的对象:
Future addRecipe(RecipeModel newRecipe) async { try { // 调用服务,获取服务器端保存后的完整食谱对象 RecipeModel savedRecipe = await _recipeService.addRecipe(newRecipe, recipes.length + 1); // 将服务器返回的对象添加到本地列表 recipes.add(savedRecipe); // 通知UI更新 notifyListeners(); } on Exception catch (e) { return e; } }
这种方式既避免了全量拉取的性能问题,又保证了本地数据和服务器完全一致。
场景二:addRecipe不返回完整对象,或需要强一致性
如果服务端不返回完整对象,或者你需要确保本地列表和服务器绝对同步,可以采用乐观更新+后续校验的方式:
Future addRecipe(RecipeModel newRecipe) async { try { // 先本地添加,即时更新UI(乐观更新) recipes.add(newRecipe); notifyListeners(); // 执行服务器添加操作 await _recipeService.addRecipe(newRecipe, recipes.length); // 拉取最新列表做同步,确保数据一致 recipes = await _recipeService.getUserRecipes(); notifyListeners(); } on Exception catch (e) { // 服务器请求失败,回滚本地操作 recipes.remove(newRecipe); notifyListeners(); return e; } }
这种方式兼顾了用户体验和数据一致性,失败时还能回滚本地状态。
额外优化建议
你的Provider初始化时,把getUserRecipesFuture赋值给了类变量,这只会在Provider创建时执行一次。如果后续列表更新后需要用FutureBuilder展示数据,建议要么每次更新后重新赋值该变量,要么在UI中直接调用对应的获取方法,避免Future数据过时。
内容的提问来源于stack exchange,提问作者Dutzun
相关产品推荐
相关产品推荐

