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

Flutter Cubit状态未正确emit:多店铺购物车计数仅首次生效

多店铺购物车Cubit的emit仅首次生效问题

我开发了一个带多店铺购物车的计数器应用,用户点击增量按钮时应触发状态更新,但仅首次操作生效——只有首个店铺的商品能添加到对应Map里。预期每个店铺拥有独立购物车,用户进入店铺点击按钮时,通过context.read<CounterCubit>().increment(...)更新状态:如果店铺名称对应的Map不存在就创建,同时添加/更新商品的价格与计数(包含价格和计数两个嵌套Map)。

状态类代码

class CounterState extends Equatable {
  Map<int?, String?> storeNameperId;
  Map<String, Map<String, String>> storeNamePriceperProduct;
  Map<String, Map<String, int>> storeNameCounterperProduct;
  int? storeId;
  String? storeName;
  CounterState({
    this.storeId,
    this.storeName,
    required this.storeNameperId,
    required this.storeNamePriceperProduct,
    required this.storeNameCounterperProduct,
  });

  @override
  List<Object?> get props => [
    storeId,
    storeName,
    storeNameperId,
    storeNamePriceperProduct,
    storeNameCounterperProduct,
  ];
}

class CounterDecrementedState extends CounterState {
  CounterDecrementedState({
    super.storeId,
    super.storeName,
    required super.storeNameperId,
    required super.storeNamePriceperProduct,
    required super.storeNameCounterperProduct,
  });

  @override
  List<Object?> get props => [storeId, storeName];
}

class CounterInitialState extends CounterState {
  CounterInitialState({
    super.storeId,
    super.storeName,
    required super.storeNameperId,
    required super.storeNamePriceperProduct,
    required super.storeNameCounterperProduct,
  });

  @override
  List<Object?> get props => [storeId, storeName];
}

class CounterIncrementedState extends CounterState {
  CounterIncrementedState({
    super.storeId,
    super.storeName,
    required super.storeNameperId,
    required super.storeNamePriceperProduct,
    required super.storeNameCounterperProduct,
  });

  @override
  List<Object?> get props => [storeId, storeName];
}

Cubit类代码(增量逻辑)

class CounterCubit extends Cubit<CounterState> {
  CounterCubit()
    : super(
        CounterInitialState(
          storeId: 0,
          storeName: '',
          storeNameperId: {},
          storeNamePriceperProduct: {},
          storeNameCounterperProduct: {},
        ),
      );

  void increment(
    String productId,
    String price,
    int inputedId,
    String storeName,
  ) {
    final prevPriceMap = state.storeNamePriceperProduct[storeName];
    final prevCounterMap = state.storeNameCounterperProduct[storeName];

    final newPriceMap =
        prevPriceMap != null
            ? Map<String, String>.from(prevPriceMap)
            : <String, String>{};
    final newCounterMap =
        prevCounterMap != null
            ? Map<String, int>.from(prevCounterMap)
            : <String, int>{};

    newPriceMap[productId] = newPriceMap[productId] ?? price;
    newCounterMap[productId] = (newCounterMap[productId] ?? 0) + 1;

    final updatedStoreNameperPriceperProduct =
        Map<String, Map<String, String>>.from(state.storeNamePriceperProduct);
    final updatedStoreNamepercounterperProduct =
        Map<String, Map<String, int>>.from(state.storeNameCounterperProduct);

    updatedStoreNameperPriceperProduct[storeName] = newPriceMap;
    updatedStoreNamepercounterperProduct[storeName] = newCounterMap;

    emit(
      CounterIncrementedState(
        storeNameperId: {...state.storeNameperId, inputedId: storeName},
        storeNamePriceperProduct: updatedStoreNameperPriceperProduct,
        storeNameCounterperProduct: updatedStoreNamepercounterperProduct,
        storeId: state.storeId,
      ),
    );
  }
}

问题根源

  1. 子类props重写错误:所有状态子类(CounterIncrementedState等)都只将storeId和storeName纳入props对比,但父类CounterState的props包含了购物车核心数据(价格、计数Map)。Cubit通过对比props判断状态是否变化,后续操作若storeId/storeName未变,即使购物车Map已更新,Cubit会判定状态无变化,不触发UI刷新。
  2. emit参数缺失:触发CounterIncrementedState时未传递storeName,可能导致状态内该字段值异常。

修复方案

1. 修正状态子类的props实现

删除所有子类的props重写,直接继承父类CounterState的props,确保所有核心状态数据都参与变化判断:

class CounterState extends Equatable {
  Map<int?, String?> storeNameperId;
  Map<String, Map<String, String>> storeNamePriceperProduct;
  Map<String, Map<String, int>> storeNameCounterperProduct;
  int? storeId;
  String? storeName;
  CounterState({
    this.storeId,
    this.storeName,
    required this.storeNameperId,
    required this.storeNamePriceperProduct,
    required this.storeNameCounterperProduct,
  });

  @override
  List<Object?> get props => [
        storeId,
        storeName,
        storeNameperId,
        storeNamePriceperProduct,
        storeNameCounterperProduct,
      ];
}

// 子类不再重写props
class CounterDecrementedState extends CounterState {
  CounterDecrementedState({
    super.storeId,
    super.storeName,
    required super.storeNameperId,
    required super.storeNamePriceperProduct,
    required super.storeNameCounterperProduct,
  });
}

class CounterInitialState extends CounterState {
  CounterInitialState({
    super.storeId,
    super.storeName,
    required super.storeNameperId,
    required super.storeNamePriceperProduct,
    required super.storeNameCounterperProduct,
  });
}

class CounterIncrementedState extends CounterState {
  CounterIncrementedState({
    super.storeId,
    super.storeName,
    required super.storeNameperId,
    required super.storeNamePriceperProduct,
    required super.storeNameCounterperProduct,
  });
}

2. 补充emit时的参数

确保CounterIncrementedState的storeName和storeId参数正确传递:

void increment(
  String productId,
  String price,
  int inputedId,
  String storeName,
) {
  final prevPriceMap = state.storeNamePriceperProduct[storeName];
  final prevCounterMap = state.storeNameCounterperProduct[storeName];

  final newPriceMap =
      prevPriceMap != null
          ? Map<String, String>.from(prevPriceMap)
          : <String, String>{};
  final newCounterMap =
      prevCounterMap != null
          ? Map<String, int>.from(prevCounterMap)
          : <String, int>{};

  newPriceMap[productId] = newPriceMap[productId] ?? price;
  newCounterMap[productId] = (newCounterMap[productId] ?? 0) + 1;

  final updatedStoreNameperPriceperProduct =
      Map<String, Map<String, String>>.from(state.storeNamePriceperProduct);
  final updatedStoreNamepercounterperProduct =
      Map<String, Map<String, int>>.from(state.storeNameCounterperProduct);

  updatedStoreNameperPriceperProduct[storeName] = newPriceMap;
  updatedStoreNamepercounterperProduct[storeName] = newCounterMap;

  emit(
    CounterIncrementedState(
      storeNameperId: {...state.storeNameperId, inputedId: storeName},
      storeNamePriceperProduct: updatedStoreNameperPriceperProduct,
      storeNameCounterperProduct: updatedStoreNamepercounterperProduct,
      storeId: inputedId, // 根据业务需求传递当前店铺ID,或保留state.storeId
      storeName: storeName, // 补充传递店铺名称
    ),
  );
}

内容的提问来源于stack exchange,提问作者Abdlrhman Bashir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:11:16