Bloc: UI does not updates if Iterable is not converted to List manually

Created on 22 Mar 2020  路  5Comments  路  Source: felangel/bloc

Assume we want to load a list of todos:

abstract class TodosState extends Equatable {
  const TodosState();

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

class TodosFilteredState extends TodosState {
  final List<Todo> todos;

  TodosFilteredState([this.todos = const []]);

  @override
  List<Object> get props => [todos];
}
class TodosFilteredByCategory extends TodosEvent {
  final int categoryId;

  TodosFilteredByCategory(this.categoryId);

  @override
  List<Object> get props => [categoryId];
}
class TodosBloc extends Bloc<TodosEvent, TodosState> {
  @override
  Stream<TodosState> mapEventToState(TodosEvent event) async* {
    // Test data
    List<Todo> todos = [Todo(id = 0, categoryId = 0), Todo(id = 1, categoryId = 1)];

    if (event is TodosFilteredByCategory) {
      yield TodosFilteredState(todos.where((todo) => todo.categoryId == event.categoryId));
    }
  }
}

If I use BlocBuilder to build UI, the UI does not build with the list of filtered todos.

The problem is at the line yield TodosFilteredState(todos.where((todo) => todo.categoryId == event.categoryId));. The where() method returns Iterable<Todo> with no compile error.

To fix the problem, I must convert it to List<Todo>: yield TodosFilteredState(todos.where((todo) => todo.categoryId == event.categoryId).toList());

Expected behavior
The UI should be rebuilt without converting Iterable<Todo> to List<Todo> manually. This kind of runtime error is difficult to detect because the compiler doesn't give any complain or warning.

question waiting for response

Most helpful comment

@felangel Thanks for you help!

I create a log delegate and print error/stacktrace from there and I get:

I/flutter ( 7135): type 'WhereIterable<Todo>' is not a subtype of type 'List<Todo>'

It's very useful! Thanks again.

All 5 comments

The same error happen when the type Map<A, B> is needed but we return a more general type Map<dynamic, dynamic>.

Hi @nguyenxndaidev 馃憢
Thanks for opening an issue!

You should override onError in your bloc if you want to handle exceptions thrown within the bloc. Let me know if that helps, thanks!

@felangel Thanks for you help!

I create a log delegate and print error/stacktrace from there and I get:

I/flutter ( 7135): type 'WhereIterable<Todo>' is not a subtype of type 'List<Todo>'

It's very useful! Thanks again.

I created an issue to improve dart compiler here https://github.com/dart-lang/sdk/issues/41155

I created an issue to improve dart compiler here dart-lang/sdk#41155

For now we can disable implicit-casts in analysis_options.yaml to get compile time error:

analyzer:
  strong-mode:
    implicit-casts: false
Was this page helpful?
0 / 5 - 0 ratings

Related issues

shawnchan2014 picture shawnchan2014  路  3Comments

Reidond picture Reidond  路  3Comments

rsnider19 picture rsnider19  路  3Comments

RobPFarley picture RobPFarley  路  3Comments

1AlexFix1 picture 1AlexFix1  路  3Comments