如何使用 bloc 并在 dart 中手动侦听 bloc.state 而不是通过 Flutter 或 AngularDart 的 bloc 管道?

Posted

技术标签:

【中文标题】如何使用 bloc 并在 dart 中手动侦听 bloc.state 而不是通过 Flutter 或 AngularDart 的 bloc 管道?【英文标题】:How do I use bloc and listen for bloc.state manually in dart and NOT through Flutter OR AngularDart's bloc pipe? 【发布时间】:2019-11-30 00:42:22 【问题描述】:

我遵循 bloc 中建议的模式,让我的 bloc 调用我的存储库,这些存储库包装了我的 api 客户端类,这些类对我的 API 进行 RESTful 调用。根据 bloc 教程中显示的模式,我将所有这些都放在 Flutter 和 Angular dart 之间共享的公共库中。我想了解如何从我也在编写的 dart CLI 程序中将 Flutter 和 Angular dart 使用的相同事件分派到我的块,并监听状态变化并获取从 API 返回的数据。 (我可以让 dart CLI 直接对所有存储库进行编程,但我想通过将事件分派到 bloc 来完成所有工作。)

我能找到的应用程序使用 Bloc 的几乎所有 Bloc 编码示例和用法都是基于 Flutter 的。 AngularDart 有一些在这里和那里(主要使用 bloc 管道)。我很少看到在其他 Dart 代码中手动使用 Bloc 的示例,例如 CLI/控制台程序在单元测试中。

我想编写一个简单的 CLI 来通过调度 Bloc 事件和响应 Bloc 的状态更改来调用我的 API。 (我非常习惯于使用 ngRx 和 Angular 来管理状态,并且我试图在这里找到一个好的模式来遵循直接 dart 代码和 dart 单元测试来调用我的 blocs。我非常习惯于 ngRx 模式的 Effects进行 API 调用和编写选择器并监听状态变化(RxJs 代码)。我很难将其转换为 dart/bloc。

我可以使用一些代码示例或建议来调用我的 bloc 并监听状态变化并从进行的 API 调用中获取状态。我想从集团外部(例如使用 .state 属性)执行此操作,而不是覆盖集团内的方法,例如转换。 (也许委托是一个好方法,我不知道.. 使用 .state 属性似乎是理想的。)

我正在查看的一个场景是将一个事件 (ItemQuery) 分派到一个集团。此事件告诉集团进行 api 调用,该调用从服务器返回项目列表。当调用开始时,bloc 立即在 mapeventtostate 中返回状态 (ItemsLoading)。当 api 调用完成时,bloc 返回状态 (ItemsLoaded) 并且该状态包含从 API 调用返回的 List。 (失败将返回 (ItemsErrorState)。

我需要先了解如何设置 dart 代码以让侦听器监视我所在区域的状态变化。一旦设置了侦听器,代码就会分派 LoadItems 事件,侦听器等待 (ItemsLoading) 和 (ItemsLoaded) 的状态更改,然后从 ItemsLoaded 状态获取 List - 不使用 Flutter 或 Angular Dart - 全部在直接 dart代码。网络上或其他地方的 stackoverlow 上的合适示例会很棒。

我已尝试通过成功使用 dart 单元测试来调用我的 bloc。

我能够让这段代码在测试中工作以测试接收到的事件的顺序(在这种情况下将列表过滤为 1 项)。但是,这并不能真正帮助我在测试期间从 ItemStateLoaded 事件中获取数据,也不能帮助我从正在编写的 Dart CLI 程序中调度 ItemQuery 事件并在 ItemStateLoaded 中获取返回的项目。

这个测试有效:

test('ItemBloc - Query filter for id == 1', () 
      ItemBloc ib = ItemBloc();

      expectLater(
          ib.state,
          emitsInOrder([
            new TypeMatcher<InitialItemState>(),
            new TypeMatcher<ItemStateLoading>(),
            new TypeMatcher<ItemStateLoaded>()
          ]));
      ApiDataConfig c = new ApiDataConfig()
        ..filter = 'id eq 1';
      ib.dispatch(ItemQuery());
    );

我有点卡住了,想看看如何从直接 dart 代码而不是通过 Flutter 或 Angular Dart 的 bloc 管道在 bloc 中使用我的 API 结果。我想从直接 dart 代码中获取 ItemStateLoaded 事件中返回的项目列表。

【问题讨论】:

【参考方案1】:

我正在回答我自己的问题(这是一个很长的问题)。答案很简单,因为我只是在学习 Dart 和 Bloc。

我为此“项目应用程序”的项目设置具有如下文件夹结构:

item_angular - angular dart“item web app”的文件夹 item_flutter - 颤振“item 移动应用”的文件夹 item_common - 两者共享的块和公共代码

上面的文件夹结构是按照 bloc 教程中的示例。我添加了另一个文件夹:

item_cli - 使用相同 Bloc 的 cli 应用程序 Angular 和 Flutter 应用程序使用的 item_common。

item_common 中调用 bloc 的示例代码是:

_handleItemEvent(ItemState state) 
  if (state is InitialItemState) 
    print('Initial Item State');
  
  if (state is ItemStateLoading) 
    print('Loading...');
  
  if (state is ItemStateLoaded) 
    print('Loaded... ' + jsonEncode(state.items[0]));
  
  if (state is ItemStateError) 
    print('Error ' + state.error);
  


main() async 
  ItemBloc ib = ItemBloc();
  ib.state.listen(_handleItemEvent, onDone: ib.dispose);
  print('Listening');
  ib.dispatch(ItemQuery());

此代码创建 ItemBloc,通过 ib.listen 订阅事件流,调度 Query 事件以告诉 Bloc 进行 Web api 调用以获取项目。 Bloc 产生 Loading 状态,然后它调用存储库层进行 API 调用以获取项目,并在成功接收到项目后产生包含已接收项目的 Loaded 状态。

输出如下:

Listening..
Initial Item State
Loading...
Loaded... [the json objects returned]

此模式回答了在 CLI 应用程序中使用直接 dart 代码直接使用 Bloc 的问题(不依赖于 Flutter 或 AngularDart)。公共库中的 Bloc 在 AngularDart 和 Flutter 以及 dart CLI 维护应用程序之间共享。

【讨论】:

以上是关于如何使用 bloc 并在 dart 中手动侦听 bloc.state 而不是通过 Flutter 或 AngularDart 的 bloc 管道?的主要内容,如果未能解决你的问题,请参考以下文章

如何在颤动中使用带有 Bloc 的冷冻包?

如何在 Hot Reload 上使用 Provider 维护 Flutter Global BloC 状态?

Dart/Flutter 中 BLoC 模式的最佳实践

如何将 Flutter Bloc 与 Firebase 电话身份验证一起使用

flutter_bloc 4.0.0如何获取事件属性参数。

超类 'Bloc<xxx, xxx>' 在 dart 中没有零参数构造函数