简体   繁体   English

BLoC Flutter 中的事件有问题。 我总是调用两个事件而不是一个

[英]Problem with events in BLoC Flutter. I always call two events instead of one

I return the state with the TodoLoadedState list in each block method.我在每个块方法中返回带有 TodoLoadedState 列表的 state。 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());但是当我在 onPressed 中调用 block 事件时,不会返回列表本身,我必须向 block 方法添加第二次调用 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.想法需要触发 1 个事件但要执行 2 个动作,第二个动作是更新列表。 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 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事件 onPressed,在任何地方你都必须使用 2 个事件来加载更新的列表

todoBloc.add(UpdateTodos(updateTodo));
todoBloc.add(LoadTodos());

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 .您正在扩展Equatable中的TodoState并将一个空列表传递给props When other states such as TodoLoadedState extend TodoState they inherit Equatable as well and the empty props.当其他状态(例如TodoLoadedState扩展TodoState时,它们也会继承Equatable和空属性。

If you're using Equatable make sure to pass all properties to the props getter.如果您使用 Equatable,请确保将所有属性传递给 props getter。

This is from bloc faq .这是来自 bloc常见问题解答 Right now all instances of your TodoLoadedState are considered equal.现在你的TodoLoadedState的所有实例都被认为是相等的。 Doesn't matter if you have a TodoLoadedState with hundreds of loadedUser or a TodoLoadedState with none.如果您有一个TodoLoadedState有数百个loadedUser或一个TodoLoadedState没有,都没有关系。 They are both considered equal and only the first time you pass a new TodoLoadedState the BlocBuilder will update.它们都被认为是相等的,并且只有在您第一次传递新的TodoLoadedState时, BlocBuilder才会更新。 The consequent ones have no effect since BlocBuilder thinks it is the same as previous one.后续的没有效果,因为BlocBuilder认为它与前一个相同。 The reason your LoadTodos event causes a rebuild is that first you emit TodoLoadingState() and then in case of success TodoLoadedState(loadedUser: _loadedTodoList) .您的LoadTodos事件导致重建的原因是首先您发出TodoLoadingState() ,然后在成功的情况下发出 TodoLoadedState 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 .所以要么不要使用Equatable ,要么确保将所有属性传递给props

class TodoLoadedState extends TodoState {
  final List<dynamic> loadedUser;

  TodoLoadedState({required this.loadedUser});
  @override
  List<Object?> get props => [loadedUser];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM