Bloc: yielding same state

Created on 22 Oct 2019  路  9Comments  路  Source: felangel/bloc

Hi,

I am trying to yield same state but bloc builder does not fired.

State:

`abstract class EventState extends Equatable {
EventState([List props = const []]) : super(props);
}

class EventLoaded extends EventState {
List events;
bool hasReachedMax;
int currentPage;
int size;

EventLoaded(
{@required this.events,
@required this.hasReachedMax,
@required this.currentPage,
@required this.size})
: super([events]);

EventLoaded copyWith(
{List events, bool hasReachedMax, int currentPage, int size}) {
return EventLoaded(
events: events ?? this.events,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
currentPage: currentPage ?? this.currentPage,
size: size ?? this.size);
}

@override
String toString() {
return "EventLoaded {currentPage: $currentPage, size: $size, hasReachedMax: $hasReachedMax}";
}
}`

Bloc:

`Stream _mapUpdateEventStatusToState(
UpdateEventStatus updateEventStatus) async* {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String token = sharedPreferences.get(Constants.tokenValue);
logger.d(token);
if (token.isEmpty) {
throw UnauthorizedException(message: "You are not logged in");
}

try {
  if (currentState is EventLoaded) {
    EventLoaded eventLoaded = currentState;
    Event updatedEvent = await FetchUtil.updateEventStatus(token,
        updateEventStatus.calculationId, updateEventStatus.eventStatus);
    int currentPage = eventLoaded.currentPage;
    int size = eventLoaded.size;
    bool hasReachedMax = eventLoaded.hasReachedMax;
    final List<Event> events = List.from(eventLoaded.events.map((event) {
      return event.calculationId == updatedEvent.calculationId
          ? updatedEvent
          : event;
    }).toList());
    logger.d(events == eventLoaded.events);
    EventLoaded eventLoaded2 = EventLoaded(
        events: events,
        currentPage: currentPage,
        hasReachedMax: hasReachedMax,
        size: size);
    logger.d(eventLoaded == eventLoaded2);
    //yield eventLoaded.copyWith(events: events);
    yield eventLoaded2;
  }
} on ApiErrorException catch (e) {
  logger.e(e);
  yield EventLoadingError(e.apiError);
} on UnauthorizedException catch (e) {
  logger.e(e);
  yield EventLoadingError(ApiError.fromMessage(e.message));
} on Exception catch (e) {
  logger.e(e);
  yield EventLoadingError(ApiError.fromMessage("Unexpected error occured"));
}

}`

question

Most helpful comment

Woooow that was related to Event's props. It is worked when I passed all props in Event 馃憤

I am updating event status and expecting state to be updated. That was a silly mistake. Sorry for your taking your time.

Again thanks for your help and this wonderful framework 馃憤 馃憤 馃

All 9 comments

Hi @altunkan 馃憢
Thanks for opening an issue!

By default, when you yield stateA where stateA == state (stateA is the same as the current bloc state), no transition will occur. If you want a transition to occur even if the yielded state is the same as the current state I would recommend you refactor your state classes not to extend Equatable. For more information check out the core concepts.

Hope that helps 馃憤

Hi @felangel ,

Thank you for your fast reply and this wonderful framework!

I noticed that my issue is related to equatable but I do not understand how it compares. I created a new list from my existing list (they are not equal btw) and my state only sending list prop to super class. How come both states are equal even though their props are not? Are this related to equatable package or dart issue?

@altunkan no problem, thank you! Your problem might be originating from the fact that your events list is of type dynamic. Can you please update your events list to have an explicit type?

class EventLoaded extends EventState {
  List<Event> events;
  ...
}

Then can you also ensure that the Event class (or whatever you named it) also extends Equatable? Thanks 馃憤

List is not dynamic, somehow it is removed while I pasted the code.

States:

abstract class EventState extends Equatable {
  EventState([List props = const []]) : super(props);
}

class EventLoaded extends EventState {
  List<Event> events;
  bool hasReachedMax;
  int currentPage;
  int size;

  EventLoaded(
      {@required this.events,
      @required this.hasReachedMax,
      @required this.currentPage,
      @required this.size})
      : super([events]);

  EventLoaded copyWith(
      {List<Event> events, bool hasReachedMax, int currentPage, int size}) {
    return EventLoaded(
        events: events ?? this.events,
        hasReachedMax: hasReachedMax ?? this.hasReachedMax,
        currentPage: currentPage ?? this.currentPage,
        size: size ?? this.size);
  }

  @override
  String toString() {
    return "EventLoaded {currentPage: $currentPage, size: $size, hasReachedMax: $hasReachedMax}";
  }
}

Bloc:
This is printing false btw

logger.d(events == eventLoaded.events);
  Stream<EventState> _mapUpdateEventStatusToState(
      UpdateEventStatus updateEventStatus) async* {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    String token = sharedPreferences.get(Constants.tokenValue);
    logger.d(token);
    if (token.isEmpty) {
      throw UnauthorizedException(message: "You are not logged in");
    }

    try {
      if (currentState is EventLoaded) {
        EventLoaded eventLoaded = currentState;
        Event updatedEvent = await FetchUtil.updateEventStatus(token,
            updateEventStatus.calculationId, updateEventStatus.eventStatus);
        int currentPage = eventLoaded.currentPage;
        int size = eventLoaded.size;
        bool hasReachedMax = eventLoaded.hasReachedMax;
        final List<Event> events = List.from(eventLoaded.events.map((event) {
          return event.calculationId == updatedEvent.calculationId
              ? updatedEvent
              : event;
        }).toList());
        logger.d(events == eventLoaded.events);
        EventLoaded eventLoaded2 = EventLoaded(
            events: events,
            currentPage: currentPage,
            hasReachedMax: hasReachedMax,
            size: size);
        logger.d(eventLoaded == eventLoaded2);
        //yield eventLoaded.copyWith(events: events);
        yield eventLoaded2;
      }
    } on ApiErrorException catch (e) {
      logger.e(e);
      yield EventLoadingError(e.apiError);
    } on UnauthorizedException catch (e) {
      logger.e(e);
      yield EventLoadingError(ApiError.fromMessage(e.message));
    } on Exception catch (e) {
      logger.e(e);
      yield EventLoadingError(ApiError.fromMessage("Unexpected error occured"));
    }
  }

Are you able to share a link to the app? It would be much easier for me to help.

You can find all code in here: https://github.com/altunkan/murphy_mobile_app/tree/master/lib/murphy/event/bloc

Btw It is working if I remove equatable.

Thanks! Why aren't you passing all properties to super?

EventLoaded(
      {@required this.events,
      @required this.hasReachedMax,
      @required this.currentPage,
      @required this.size})
      : super([events, hasReachedMax, currentPage, size]);

Also, same goes for your Event

Event(
      {@required this.calculationId,
      @required this.event,
      @required this.murphy,
      @required this.eventTime,
      @required this.status})
      : super([calculationId, event, murphy, eventTime, status]);

Woooow that was related to Event's props. It is worked when I passed all props in Event 馃憤

I am updating event status and expecting state to be updated. That was a silly mistake. Sorry for your taking your time.

Again thanks for your help and this wonderful framework 馃憤 馃憤 馃

No problem! Glad I was able to help 馃槃

Was this page helpful?
0 / 5 - 0 ratings

Related issues

craiglabenz picture craiglabenz  路  3Comments

hivesey picture hivesey  路  3Comments

timtraversy picture timtraversy  路  3Comments

ricktotec picture ricktotec  路  3Comments

rsnider19 picture rsnider19  路  3Comments