Reputation: 1301
I return the state with the TodoLoadedState list in each block method. But when I call the block event in onPressed, the list itself is not returned and I have to add a second call to the block method todoBloc.add(LoadTodos()); But that's not correct. Ideas need to trigger 1 event but to perform 2 actions, the second action is to update the list. Thanks in advance!
todo_bloc
class TodoBloc extends Bloc<TodoEvent, TodoState> {
final TodoRepository todoRepository;
TodoBloc(this.todoRepository) : super(TodoEmptyState()) {
on<LoadTodos>((event, emit) async {
emit(TodoLoadingState());
try {
final List<Todo> _loadedTodoList = await todoRepository.getAllTodos();
emit(TodoLoadedState(loadedUser: _loadedTodoList));
} catch (_) {
emit(TodoErrorState());
}
});
on<CreateTodos>((event, emit) async {
// Todo todo = Todo(description: event.task, isDone: false);
await todoRepository.insertTodo(event.todo);
final List<Todo> _loadedTodoList = await todoRepository.getAllTodos();
emit(TodoLoadedState(loadedUser: _loadedTodoList));
});
on<DeleteTodos>((event, emit) async {
await todoRepository.deleteTodo(event.id);
final List<Todo> _loadedTodoList = await todoRepository.getAllTodos();
emit(TodoLoadedState(loadedUser: _loadedTodoList));
});
on<UpdateTodos>((event, emit) async {
await todoRepository.updateTodo(event.todo);
final List<Todo> _loadedTodoList = await todoRepository.getAllTodos();
emit(TodoLoadedState(loadedUser: _loadedTodoList));
});
}
}
todo_list
class TodoList extends StatelessWidget {
@override
Widget build(BuildContext context) {
final TodoBloc todoBloc = context.read<TodoBloc>();
return BlocBuilder<TodoBloc, TodoState>(builder: (context, state) {
if (state is TodoEmptyState) {
return const Center(
child: Text(
'No Todo',
style: TextStyle(fontSize: 20.0),
),
);
}
if (state is TodoLoadingState) {
return const Center(child: CircularProgressIndicator());
}
if (state is TodoLoadedState) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: state.loadedUser.length,
itemBuilder: (context, index) => ListTile(
title: Column(children: [
Text('${state.loadedUser[index].description}'),
Text('${state.loadedUser[index].id}'),
]),
trailing: IconButton(
onPressed: () {
todoBloc.add(DeleteTodos(id: state.loadedUser[index].id));
todoBloc.add(LoadTodos());
},
home_page
class HomePage extends StatelessWidget {
final todoRepository = TodoRepository();
@override
Widget build(BuildContext context) {
return BlocBuilder<TodoBloc, TodoState>(builder: (context, state) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Todos'),
),
body: SingleChildScrollView(
child: Column(
children: [
TodoList(),
],
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add, size: 32, color: Colors.white),
onPressed: () {
final TodoBloc todoBloc = context.read<TodoBloc>();
final _todoDescriptionFromController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (builder) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
color: Colors.transparent,
child: Container(
todo_state
abstract class TodoState extends Equatable {
const TodoState();
@override
List<Object> get props => [];
}
class TodoLoadingState extends TodoState {}
class TodoEmptyState extends TodoState {}
class TodoLoadedState extends TodoState {
List<dynamic> loadedUser;
TodoLoadedState({required this.loadedUser});
}
class TodoErrorState extends TodoState {}
todo_event
abstract class TodoEvent extends Equatable {
const TodoEvent();
@override
List<Object> get props => [];
}
class LoadTodos extends TodoEvent {}
class CreateTodos extends TodoEvent {
final Todo todo;
const CreateTodos(this.todo);
}
class UpdateTodos extends TodoEvent {
final Todo todo;
const UpdateTodos(this.todo);
}
class DeleteTodos extends TodoEvent {
final int id;
const DeleteTodos({required this.id});
}
class QueryTodo extends TodoEvent {}
event onPressed, everywhere you have to use 2 events to load the updated list
todoBloc.add(UpdateTodos(updateTodo));
todoBloc.add(LoadTodos());
Upvotes: 1
Views: 1564
Reputation: 935
This is the culprit:
abstract class TodoState extends Equatable {
const TodoState();
@override
List<Object> get props => [];
}
You are extending Equatable
in TodoState
and passing an empty list to props
. When other states such as TodoLoadedState
extend TodoState
they inherit Equatable
as well and the empty props.
If you're using Equatable make sure to pass all properties to the props getter.
This is from bloc faq. Right now all instances of your TodoLoadedState
are considered equal. Doesn't matter if you have a TodoLoadedState
with hundreds of loadedUser
or a TodoLoadedState
with none. They are both considered equal and only the first time you pass a new TodoLoadedState
the BlocBuilder
will update. The consequent ones have no effect since BlocBuilder
thinks it is the same as previous one. The reason your LoadTodos
event causes a rebuild is that first you emit TodoLoadingState()
and then in case of success TodoLoadedState(loadedUser: _loadedTodoList)
. This alternating between two different states makes it work.
So either don't use Equatable
or make sure to pass all the properties to props
.
class TodoLoadedState extends TodoState {
final List<dynamic> loadedUser;
TodoLoadedState({required this.loadedUser});
@override
List<Object?> get props => [loadedUser];
}
Upvotes: 4