使用distinct属性时,如何让StoreConnector识别ViewModel的列表更新?
问题:让StoreConnector识别ViewModel列表更新并保留distinct性能优化
我正尝试让StoreConnector识别_ViewModel中列表的更新,以刷新屏幕上的UI列表,同时为了性能优化,打算使用StoreConnector的distinct属性。想知道有没有办法从store生成能被StoreConnector识别的列表?
现有代码示例
_GroceryViewModel
class _GroceryViewModel extends Equatable { final int amountOfItems; final List<String> meats; _SmartWearViewModel({ // 注:此处构造函数名疑似笔误,应为_GroceryViewModel required this.amountOfItems, required this.meats, }); @override List<Object?> get props => [ this.amountOfItems, this.meats, ]; }
_ViewModel Factory
factory _ViewModel.create(Store<AppState> store) { var itemList = store.state.itemState!.meats! .map((e) => _GroceryViewModel( amountOfItems: e.amountOfItems, meats: e.meats, )) .toList(); return _ViewModel( itemList: itemList, ); }
目前仅尝试过移除distinct属性,此时功能正常,但无法达成性能优化的目标;也尝试过从store重新创建列表,但没有效果,想了解其他可行的解决方法?
解决方法
1. 确保_ViewModel继承Equatable并正确声明props
你返回的_ViewModel必须继承Equatable,将itemList加入props列表,这样distinct才能通过内容对比判断是否需要刷新UI:
class _ViewModel extends Equatable { final List<_GroceryViewModel> itemList; _ViewModel({required this.itemList}); @override List<Object?> get props => [itemList]; }
2. 让Store状态中的列表保持不可变性
在Store的Reducer更新状态时,必须生成新的列表实例而不是修改原有列表。这样每次列表内容变化时,Store中的列表引用会更新,ViewModel的itemList也会随之更新:
// 示例Reducer代码(更新meats列表时) ItemState updateMeats(ItemState state, AddMeatAction action) { return state.copyWith( // 使用展开操作符创建新列表,确保引用变化 meats: [...state.meats, action.newMeat] // 或使用不可变列表强化约束 // meats: List.unmodifiable([...state.meats, action.newMeat]) ); }
3. 修正_GroceryViewModel的笔误并确保列表内容可被对比
将构造函数名修正为_GroceryViewModel,Equatable会自动对比meats列表中的每个字符串内容,无需额外处理:
class _GroceryViewModel extends Equatable { final int amountOfItems; final List<String> meats; _GroceryViewModel({ required this.amountOfItems, required this.meats, }); @override List<Object?> get props => [amountOfItems, meats]; }
4. 正确启用distinct属性
在StoreConnector中开启distinct: true,此时只有当itemList的内容(或元素内容)真正变化时,才会触发UI刷新,兼顾功能与性能:
StoreConnector<AppState, _ViewModel>( converter: _ViewModel.create, distinct: true, builder: (context, vm) { return ListView.builder( itemCount: vm.itemList.length, itemBuilder: (context, index) { final item = vm.itemList[index]; return ListTile( title: Text('肉类:${item.meats.join(', ')}'), subtitle: Text('数量:${item.amountOfItems}'), ); }, ); }, )
原问题的核心原因
- 移除
distinct时,Store每次状态变化都会强制刷新UI,所以功能正常但性能损耗大; - 直接重新创建列表但未处理列表不可变性和Equatable对比逻辑,要么导致无意义的刷新(引用变了但内容没变),要么导致内容变化时无法触发刷新(引用没变但内容变了)。
内容的提问来源于stack exchange,提问作者Sipho Sikakane
相关产品推荐
相关产品推荐

