首页 > 解决方案 > 如何使用 bloc 并在 dart 中手动侦听 bloc.state 而不是通过 Flutter 或 AngularDart 的 bloc 管道?

问题描述

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

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

我想编写一个简单的 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 - 全部采用直飞镖代码。网络上或其他地方的 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 代码中使用我的 API 结果,而不是通过 Flutter 或 Angular Dart 的 bloc 管道。我想从直接飞镖代码中获取在 ItemStateLoaded 事件中返回的项目列表。

标签: dartbloc

解决方案


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

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

  • item_angular - 角度飞镖“item web app”的文件夹
  • item_flutter - 颤振“项目移动应用”的文件夹
  • item_common - 两者之间共享的块和公共代码

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

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

在 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 代码(不依赖于 Flutter 或 AngularDart)直接使用 Bloc 的问题。公共库中的 Bloc 在 AngularDart 和 Flutter 以及 dart CLI 维护应用程序之间共享。


推荐阅读