Riverpod中StateNotifier修改购物车数量后如何触发UI状态更新
问题根因
StateNotifier的状态刷新触发条件是state变量被赋值为一个新的对象实例,仅修改state内部嵌套对象的属性时,state本身的内存引用没有变化,不会通知监听的UI组件刷新,你代码里打印same就是这个原因。
正确实现方案
第一步:改造数据模型为不可变结构
所有自定义模型类的属性全部用final修饰,同时添加copyWith方法用于生成修改指定属性后的新实例,避免原地修改对象。
以你用到的两个模型为例,手写实现参考:
// 对应pricing数组的元素类型 class Pricing { final int? quantity; final int? moq; // 补充你的其他业务属性 Pricing({ this.quantity, this.moq, // 其他属性初始化 }); Pricing copyWith({ int? quantity, int? moq, // 其他属性传参 }) { return Pricing( quantity: quantity ?? this.quantity, moq: moq ?? this.moq, // 其他属性赋值 ); } } // 对应BuyingOptionsModel class BuyingOptionsModel { final List<Pricing>? pricing; // 补充你的其他业务属性 BuyingOptionsModel({ this.pricing, // 其他属性初始化 }); BuyingOptionsModel copyWith({ List<Pricing>? pricing, // 其他属性传参 }) { return BuyingOptionsModel( pricing: pricing ?? this.pricing, // 其他属性赋值 ); } }
如果想减少手写代码量,可以用freezed等代码生成工具自动生成不可变类和copyWith逻辑。
第二步:修改增减数量的逻辑,生成新状态赋值给state
不要原地修改state内部的属性,每次修改都构造全新的模型实例,再赋值给state触发刷新。修改后的CartList2代码如下:
class CartList2 extends StateNotifier<AsyncValue<BuyingOptionsModel>> { CartList2() : super(const AsyncValue.loading()) { _getData(); } Future<void> _getData() async { state = const AsyncValue.loading(); state = await AsyncValue.guard(() async { final json = await ProductRepository().buyingOptions(product_id: 11361); return BuyingOptionsModel.fromJson(json); }); } void increment(int index) { // 非数据状态直接拦截 if (!state.hasValue) return; final currentData = state.value!; final pricingList = currentData.pricing ?? []; if (index >= pricingList.length) return; final targetItem = pricingList[index]; final newQuantity = (targetItem.quantity ?? 0) + (targetItem.moq ?? 1); // 生成新的pricing数组,替换对应索引的元素 final newPricingList = [ ...pricingList.sublist(0, index), targetItem.copyWith(quantity: newQuantity), ...pricingList.sublist(index + 1), ]; // 赋值新的状态实例,触发UI刷新 state = AsyncValue.data(currentData.copyWith(pricing: newPricingList)); } void decrement(int index) { if (!state.hasValue) return; final currentData = state.value!; final pricingList = currentData.pricing ?? []; if (index >= pricingList.length) return; final targetItem = pricingList[index]; final currentQty = targetItem.quantity ?? 0; final moq = targetItem.moq ?? 1; // 数量小于等于最小起订量时不允许继续减 if (currentQty <= moq) return; final newQuantity = currentQty - moq; final newPricingList = [ ...pricingList.sublist(0, index), targetItem.copyWith(quantity: newQuantity), ...pricingList.sublist(index + 1), ]; state = AsyncValue.data(currentData.copyWith(pricing: newPricingList)); } }
注意事项
- 原代码里increment/decrement方法加的
async关键字没有意义,这两个方法内部没有异步逻辑,不需要加 - 不要给不可变模型的属性用非final修饰,否则很容易写出原地修改属性不触发刷新的问题
- StateNotifier不会做状态的深度变更监听,只有state引用变化才会触发更新,所有状态修改都要遵循不可变更新的规则
内容的提问来源于stack exchange,提问作者Suman Poudyal
相关产品推荐
相关产品推荐

