You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 07:44:57