Flutter - Bloc only emits state when the state is not extending Equatable

Viewed 579

I recently started using bloc and im stuck here.

I have a state:

class BasketState extends Equatable{
  final Map<Item, int> itemsOrdered;

  BasketState(this.itemsOrdered);

  @override
  List<Object> get props => [itemsOrdered]
}

And the following bloc:

class BasketBloc extends Bloc<BasketEvent, BasketState> {
  Map<Item, int> _itemsOrdered = {};
  BasketBloc() : super(BasketState({}));

  @override
  Stream<BasketState> mapEventToState(BasketEvent event) async* {
    if (event is BasketAdd) {
      _itemsOrdered.putIfAbsent(event.item, () => event.amount);
    } else if (event is BasketRemove) {
      _itemsOrdered.remove(event.item);
    }
    yield BasketState(_itemsOrdered);
  }
}

Only the first time I send the BasketAdd event the bloc emits the state, then if I send the BasketAdd event again, the bloc emits nothing.

The only thing that worked is to remove the Equatable from the state, and I dont know why.

Am I doing something wrong?

2 Answers

Equatable is using that get props function to do the comparison.

Change

  @override
  List<Object> get props => throw UnimplementedError();

to

  @override
  List<Object> get props => [itemsOrdered];

and try again

EDIT: The answer is in the comments now but another possible problem is mutability. In this case, rather than yielding itemsOrdered we should yield a new Map each time.

  yield BasketState(new Map<Item, int>.from(itemsOrdered));

From Docs

Equatable properties should always be copied rather than modified. If an Equatable class contains a List or Map as properties, be sure to use List.from or Map.from respectively to ensure that equality is evaluated based on the values of the properties rather than the reference.

yield BasketState(Map<Item, int>.from(itemsOrdered));
Related