Flutter BLoC mapEventToState 仅在第一次事件时被调用,而不会在每次事件下次触发时调用

2023-12-31

I have Courses and Tasks. Each Course有很多Tasks。这就是为什么我在应用程序中使用不同的屏幕来显示课程列表,并且在点击课程后,我将导航到下一个屏幕 - 任务列表。这是我的onTap课程列表方法:

                          onTap: () {
                            TasksPageLoadedEvent pageLoadedEvent =
                                TasksPageLoadedEvent(
                              courseId: state.courses[index].id,
                              truckNumber: this.truckNumber,
                            );
                            serviceLocator<TaskBloc>().add(pageLoadedEvent);
                            Routes.sailor(
                              Routes.taskScreen,
                              params: {
                                Routes.courseNumber:
                                    state.courses[index].courseNumber,
                                Routes.truckNumber: this.truckNumber,
                                Routes.courseId: state.courses[index].id,
                              },
                            );
                          }

我创建一个TasksPageLoadedEvent,将其传递给TaskBloc并导航至“任务”页面。

这里是TaskBloc以及它如何处理映射事件 - 状态:

@override
  Stream<TaskState> mapEventToState(
    TaskEvent event,
  ) async* {
    if (event is TasksLoadingEvent) {
      yield TasksLoadingState();
    } else if (event is TasksReloadingErrorEvent) {
      yield TasksErrorState();
    } else if (event is TasksFetchedFailureEvent) {
      yield TaskFetchedStateFailureState(error: event.failure);
    } else if (event is TasksPulledFromServerEvent) {
      yield TasksPulledFromServerState(
        truckNumber: event.truckNumber,
        courseNumber: event.courseNumber,
        courseId: event.courseId,
      );
    } else if (event is TasksPageLoadedEvent) {
      yield TasksLoadingState();

      final networkInfoEither = await this.getNetworkInfoQuery(NoQueryParams());

      yield* networkInfoEither.fold((failure) async* {
        yield TasksErrorState();
      }, (success) async* {
        if (success) {
          final getTasksEither = await getTasksQuery(
            GetTasksParams(
              truckNumber: event.truckNumber,
              courseId: event.courseId,
            ),
          );

          yield* getTasksEither.fold((failure) async* {
            yield TaskFetchedStateFailureState(error: "coursesDatabaseError");
          }, (result) async* {
            if (result != null) {
              yield TasksFetchedState(tasks: result);
            } else {
              yield TaskFetchedStateFailureState(
                  error: "coursesFetchFromDatabaseError");
            }
          });
        } else {
          yield TasksNoInternetState();
        }
      });
    }
  }

当我导航到“任务”页面时,BlocBuilder检查状态并相应地处理建筑物。我有一个返回功能,可以导航回课程页面:

              onPressed: () {
                serviceLocator<CourseBloc>().add(
                  CoursesPageLoadedEvent(truckNumber: this.truckNumber),
                );
                Navigator.of(context).pop(true);
              },

这会触发前一页的类似事件并重新加载。

如果我想去另一门课程并查看其任务,我面临的问题就会发生。如果我点击列表中的另一个项目并因此触发一个新的TasksPageLoadedEvent(具有新属性)mapEventToState()根本没有被叫到。

我之前也遇到过类似的 BLoC 问题,但他们是关于BlocListener和国家延长Equatable。这就是为什么我的活动没有延长Equatable(虽然我不确定这是否是这里的问题)。但仍然没有任何反应。

这是我的活动:

abstract class TaskEvent {
  const TaskEvent();
}

class TasksPageLoadedEvent extends TaskEvent {
  final String truckNumber;
  final int courseId;

  TasksPageLoadedEvent({
    this.truckNumber,
    this.courseId,
  });
}

class TasksFetchedFailureEvent extends TaskEvent {
  final String failure;

  TasksFetchedFailureEvent({
    this.failure,
  });
}

class TasksLoadingEvent extends TaskEvent {}

class TasksReloadingErrorEvent extends TaskEvent {}

class TasksPulledFromServerEvent extends TaskEvent {
  final String courseNumber;
  final String truckNumber;
  final int courseId;

  TasksPulledFromServerEvent({
    @required this.courseNumber,
    @required this.truckNumber,
    @required this.courseId,
  });
}

我应该如何在每个页面使用两个 BLoC 来处理两个页面之间的来回切换?


好吧,我自己找到了答案!

当然,正如费德里克·乔纳森所暗示的那样,问题是集团的例子。我正在使用 flutter 包 get_it 创建的单例实例。如果您正在实现依赖注入(例如对于干净的架构),这非常有用。

所以这一个例子就是问题所在。

幸运的是,这个包已经实现了简洁的方法resetLazySingleton<T>.

返回时调用它会重置该小部件中使用的块。因此,当我再次导航到“任务”页面时,我正在使用该块的相同但重置的实例。

Future<bool> _onWillPop() async {
    serviceLocator.resetLazySingleton<TaskBloc>(
      instance: serviceLocator<TaskBloc>(),
    );

    return true;
  }

我希望这个答案能够帮助那些遇到单例、依赖注入以及在带有 bloc 的 flutter 应用程序中来回问题的人。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter BLoC mapEventToState 仅在第一次事件时被调用,而不会在每次事件下次触发时调用 的相关文章

随机推荐