Riverpod监听Provider状态变更后销毁,列表过滤失效求助
问题排查与修复方案
核心问题根源
- FutureProvider依赖监听失效:
recordListFiltered中先await异步Provider,后续的ref.watch(etiquetaSelecProvider)无法被Riverpod正确追踪依赖,导致标签变更时Provider不仅不重新计算,反而被销毁。 - 过滤逻辑类型不匹配:用
Etiqueta的Set判断是否包含Records对象,条件永远为true,过滤完全无效。 - UI与Provider状态不同步:
ChipEtiqueta本地维护filters状态,未从Provider读取真实选中状态,导致UI显示与实际过滤条件不一致。 - Etiqueta对象相等性判断缺失:Set的
contains依赖==和hashCode方法,若未重写则无法正确识别相同标签。
分步修复方案
1. 修正recordListFiltered Provider的依赖监听与过滤逻辑
调整代码顺序,确保同步依赖优先被监听,同时修正过滤条件(假设Records对象包含etiquetas属性存储关联标签):
@Riverpod(keepAlive: true) FutureOr<List<Records>> recordListFiltered(RecordListFilteredRef ref) async { // 先监听同步依赖,再处理异步订单列表 final selectedEtiquetas = ref.watch(etiquetaSelecProvider); final recordsList = await ref.watch(cajaControllerProvider.future); print('当前选中标签: $selectedEtiquetas'); // 过滤逻辑:排除包含任意选中标签的订单(可根据需求调整) final updatedList = recordsList.where((record) { if (selectedEtiquetas.isEmpty) return true; // 无选中标签时返回全部订单 return !record.etiquetas.any((etiqueta) => selectedEtiquetas.contains(etiqueta)); }).toList(); return updatedList; }
2. 修复ChipEtiqueta的状态同步问题
移除本地filters状态,直接从Provider读取选中状态,确保UI与数据源完全同步:
// 改为ConsumerWidget,无需本地状态 class ChipEtiqueta extends ConsumerWidget { final Etiqueta etiqueta; final bool isFilter; final VoidCallback? funct; const ChipEtiqueta({ required this.etiqueta, this.isFilter = false, this.funct, super.key, }); @override Widget build(BuildContext context, WidgetRef ref) { // 直接从Provider获取选中标签集合 final selectedEtiquetas = ref.watch(etiquetaSelecProvider); final selecEtiquetasProv = ref.read(etiquetaSelecProvider.notifier); return isFilter ? FilterChip( label: Text( etiqueta.nombre, style: Theme.of(context) .textTheme .labelSmall! .copyWith(fontSize: 10.fSize, fontWeight: FontWeight.w600), ), // 用Provider状态判断选中状态 selected: selectedEtiquetas.contains(etiqueta), onSelected: (bool selected) { if (selected) { selecEtiquetasProv.addEtiquetaSelec(etiqueta); } else { selecEtiquetasProv.deleteEtiquetaSelec(etiqueta); } }, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(50))), padding: const EdgeInsets.symmetric(vertical: -7, horizontal: 0), labelPadding: const EdgeInsets.symmetric(horizontal: 5, vertical: -3), ) : Chip( label: Text( etiqueta.nombre, style: Theme.of(context) .textTheme .labelSmall! .copyWith(fontSize: 10.fSize, fontWeight: FontWeight.w600), ), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(50))), padding: const EdgeInsets.symmetric(vertical: -7, horizontal: 0), labelPadding: const EdgeInsets.symmetric(horizontal: 5, vertical: -3), ); } }
3. 给Etiqueta模型添加相等性判断
在etiquetas_model.dart中重写==和hashCode方法,确保Set能正确识别相同标签:
class Etiqueta { final String nombre; // 若有唯一ID属性,建议用ID判断相等性 Etiqueta({required this.nombre}); @override bool operator ==(Object other) => identical(this, other) || other is Etiqueta && runtimeType == other.runtimeType && nombre == other.nombre; @override int get hashCode => nombre.hashCode; }
4. 优化标签删除方法(可选)
简化删除逻辑,确保状态更新符合Riverpod要求:
void deleteEtiquetaSelec(Etiqueta etiqueta) { state = state.where((e) => e.nombre != etiqueta.nombre).toSet(); }
验证要点
- 点击标签时,检查控制台输出确认
etiquetaSelecProvider状态是否正确更新 - 观察
recordListFiltered是否在标签变更时重新计算并返回过滤后的列表 - 确认Chip的选中状态与Provider中的状态完全一致
内容的提问来源于stack exchange,提问作者Nicolas Sicard
相关产品推荐
相关产品推荐

