为什么我的 Bloc Listener 在同一事件中发生多次触发时,不监听状态的变化?

huangapple go评论70阅读模式
英文:

Why isn't my Bloc Listener listening to state changes during multiple emits in the same event?

问题

Bloc Listener在同一事件中不监听状态的多次变化。

我正在执行异步操作,从存储库中获取即将到来的行程列表。在获取之前,我会发出加载状态的通知。在获取之后,我会发出成功状态,并附带列表。

基本上,在同一事件中有两次发出。

以下是您的BLOC部分的翻译:

Future<void> _onTripsFetchUpcoming(TripsEvent event, Emitter emit) async {
    await tripsBlocTryCatchWrapper(() async {
      if (event is TripsFetchUpcoming) {
        emit(
          state.copyWith(
            status: TripsStatus.fetchUpcomingTrips,
            loadingMessage: "正在获取即将到来的行程。",
          ),
        );
        final res =
            await _tripsRepository.getAllUpcomingTrips(event.opId.toString());
            
        emit(
          state.copyWith(
            successMessage: "成功获取所有即将到来的行程。",
            status: TripsStatus.fetchedUpcomingTrips,
            upcomingTrips: res,
          ),
        );
      }
    }, emit);
  }

在另一个小部件中,我设置了一个Bloc Listener来监听这些变化并触发显示模态对话框的ModalCubit。为了测试,我尝试使用一个简单的snackbar。

BlocListener<TripsBloc, TripsState>(
  listenWhen: (previous, current) =>
    previous.status != current.status,
  listener: (context, tripsState) {
    print(tripsState.status);
    if (tripsState.status.isLoading ||
      tripsState.status.isFetchingUpcomingTrips) {
      context.read<ModalCubit>().showModal(
        ModalLoadingChild(
          subject: "行程",
          message: tripsState.loadingMessage,
        ),
        "loading",
        stopClose: true,
      );
    } else if (tripsState.status.isFetchedUpcomingTrips ||
      tripsState.status.isSuccess) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text(tripsState.status.toString())));
        print("成功");
        ScaffoldMessenger.of(context)
          .showSnackBar(SnackBar(content: Text(tripsState.status.toString())));
        context.read<ModalCubit>().showModal(
          ModalSuccessChild(
            subject: "行程",
            message: tripsState.successMessage,
          ),
          "success",
        );
    }
  },
);

在上述监听器中,加载状态的发出被监听到,但不会捕获第二个成功状态的发出。

即使在ModalCubit Listener中,只有加载状态显示,而不是InActive状态。

BlocListener<ModalCubit, ModalState>(
  listener: (context, state) {
    ScaffoldMessenger.of(context)
      .showSnackBar(SnackBar(content: Text(state.toString())));
  },
)

编辑 1.0:

在await _tripsRepository.getAllUpcomingTrips()之后的任何emit()都不会被BlocListener捕获,这在我的所有bloc中都是一样的情况。

编辑 1.1 - 添加包装器。

Future<void> tripsBlocTryCatchWrapper<T>(
    FutureOr<T> Function() tryBlock, void Function(TripsState) emit) async {
  try {
    await tryBlock();
  } on DioError catch (e) {
    emit(
      TripsError(
        message: e.error.toString(),
      ),
    );
  } catch (e) {
    emit(
      TripsError(
        message: "在获取个人资料时出现问题。",
      ),
    );
  }
}

编辑 2.0:

我想要一个在全局范围内实施Bloc监听器的解决方案。当我尝试将它设置为MaterialApp的直接子级时,出现了问题,而在个别的主页小部件中,它是有效的。

英文:

Bloc Listener is not listening to the state changes during multiple emits in same event.

I am performing an async operation to fetch a list of upcoming trips from the repository. Before fetching i am emitting a loading state. After fetching I am emitting a success state along with the list.

Basically there are two emits in same event.
BLOC:

Future&lt;void&gt; _onTripsFetchUpcoming(TripsEvent event, Emitter emit) async {
    await tripsBlocTryCatchWrapper(() async {
      if (event is TripsFetchUpcoming) {
        emit(
          state.copyWith(
            status: TripsStatus.fetchUpcomingTrips,
            loadingMessage: &quot;Fetching upcoming trips.&quot;,
          ),
        );
        final res =
            await _tripsRepository.getAllUpcomingTrips(event.opId.toString());
            
        emit(
          state.copyWith(
            successMessage: &quot;Successfully fetched all upcoming trips.&quot;,
            status: TripsStatus.fetchedUpcomingTrips,
            upcomingTrips: res,
          ),
        );
      }
    }, emit);
  }

I have setup a bloc listener in another widget to listen to these changes and trigger the ModalCubit which shows a modal. For testing I tried with a simple snack bar.

BlocListener&lt;TripsBloc, TripsState&gt;(
                    listenWhen: (previous, current) =&gt;
                        previous.status != current.status,
                    listener: (context, tripsState) {
                      
                      print(tripsState.status);
                      if (tripsState.status.isLoading ||
                          tripsState.status.isFetchingUpcomingTrips) {
                        context.read&lt;ModalCubit&gt;().showModal(
                              ModalLoadingChild(
                                subject: &quot;Trips&quot;,
                                message: tripsState.loadingMessage,
                              ),
                              &quot;loading&quot;,
                              stopClose: true,
                            );
                      } else if (tripsState.status.isFetchedUpcomingTrips ||
                          tripsState.status.isSuccess) {
                            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          content: Text(tripsState.status.toString())));
                        print(&quot;SUCCESSS&quot;);
                        //  context.read&lt;ModalCubit&gt;().hideModal();
                        ScaffoldMessenger.of(context)
                            .showSnackBar(SnackBar(content: Text(tripsState.status.toString())));
                        context.read&lt;ModalCubit&gt;().showModal(
                              ModalSuccessChild(
                                subject: &quot;Trips&quot;,
                                message: tripsState.successMessage,
                              ),
                              &quot;success&quot;,
                            );
                      }
                    },
                  );

In the above listener, the loading state emit is being recognized by the listener but it is not picking up the second emit(Success).

Even in ModalCubit Listener only the loading state is shown and not the InActive State.

BlocListener&lt;ModalCubit, ModalState&gt;(
      listener: (context, state) {
        ScaffoldMessenger.of(context)
            .showSnackBar(SnackBar(content: Text(state.toString())));
      },
)

EDIT 1.0

Any emit() after the await _tripsRepository.getAllUpcomingTrips(), is not picked up by the BlocListener, this is the same case in all my blocs.

EDIT 1.1 - Adding the wrapper.

Future&lt;void&gt; tripsBlocTryCatchWrapper&lt;T&gt;(
    FutureOr&lt;T&gt; Function() tryBlock, void Function(TripsState) emit) async {
  try {
    await tryBlock();
  } on DioError catch (e) {
    emit(
      TripsError(
        message: e.error.toString(),
      ),
    );
  } catch (e) {
    emit(
      TripsError(
        message: &quot;Something went wrong in profile.&quot;,
      ),
    );
  }
}

EDIT 2.0:

I would like a solution to implement the bloc listener globally, when I tried with the individual home widget it worked, whereas when I set it as a direct child to MaterialApp, the issue is as described.

答案1

得分: 0

当我将监听器提取为单独的小部件,并将其用作我需要的每个屏幕的包装器时,它就会起作用。它在调用后的某个地方被大多数情况下从小部件树中移除。

英文:

When i extracted the listener into a separate widget as used it as a wrapper to every single screen i need, then it will work. It is mostly getting removed from the widget tree somewhere after invocation.

huangapple
  • 本文由 发表于 2023年5月22日 04:11:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76301747.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定