【问题标题】:Nested data and BLoCs in FlutterFlutter 中的嵌套数据和 BLoC
【发布时间】:2019-01-26 00:34:35
【问题描述】:

我的 Flutter 应用具有以下一般结构:

  1. 初始屏幕显示联系人对象列表。用户可以点击一个联系人,这会调出
  2. 一个详细信息屏幕,可让用户查看整个联系信息,并临时修改任何详细信息。用户可以
  3. 关闭屏幕而不保存更改,或者
  4. 点击保存按钮,永久更新联系人,完成后返回初始屏幕。

我正在使用 FireStore。该列表是用Stream<QuerySnapshots> 构建的,当用户点击一个项目时,应用程序的路由器会解析路由名称(例如/contacts/123),创建相应的DocumentReference 并将其转发到详细信息屏幕的初始化程序,然后使用@ 987654324@ 加载详细信息,DocumentReference.updateData 保存更改。效果很好——但只是概念证明。

现在我想隐藏 FireStore 和 BLoC 后面的剩余业务逻辑。这就引出了一些问题:

  1. 据我了解,将业务逻辑排除在 UI 之外意味着我应该坚持使用命名路由,并让详细信息屏幕以某种方式使用路由详细信息通过 BLoC 检索相关联系人数据。这是真的吗?最好的解决方案是什么?
  2. 如何使用 BLoC 订阅嵌套数据?我希望详细信息屏幕可以观察数据变化,以便在数据过时时向用户发出警告。禁止在 BLoC 上使用函数(类似于 streamOfContact(contact) -> Stream<Contact>),那么我该如何使用 Sinks 呢?还是在不破坏 BLoC 模式的情况下通常有不同的方法来做到这一点?我对这一切都很陌生,所以很可能我忽略了一些重要的事情。
  3. 类似问题:如何更新特定联系人?

我在网上找到的教程只处理根数据(例如,将购物车项目添加到购物车、处理用户身份验证……),但我还没有看到展示嵌套数据的示例。非常感谢任何帮助!

【问题讨论】:

  • 您不需要使用路由器来处理这个问题,例如,您可以简单地映射联系人列表,当我点击一个联系人时,您将传递所点击联系人的相应值/详细信息(即:ContactDetails(details:allContacts[uid]))在这种情况下 allContacts 将是 的映射,ContactDetails 小部件将是一个哑小部件,仅显示从联系人列表传递的联系人详细信息
  • 谢谢,这会起作用,但我希望在联系人更改时更新详细信息小部件。联系人在多个应用程序(和用户)之间共享,因此可以随时更改。我更喜欢使用命名路由的原因是因为这样我就可以从应用程序中的任何位置打开联系人详细信息,而不仅仅是从概览列表中。
  • 这有点太宽泛了。虽然我理解您的担忧,但我无法提供有限的答案。你不能在一个具体点上重新提出你的问题吗?如果需要,您可以随意提出其他问题
  • 嗨,你找到方法了吗?如果是这样,你能分享一些代码吗?我也在为这种模式而苦苦挣扎。谢谢。
  • 在下面 Bofomer 的出色回答的帮助下,我能够解决所有问题。如果您对我上面帖子中的具体细节有疑问,请详细说明 - 或者更好的是,考虑发布您自己的问题并将其链接到此处。

标签: dart flutter


【解决方案1】:

1) 路由和导航由 UI 层负责。这意味着 UI 层必须调用Navigator.push[Named](...)

如果有意义,您可以移动决定应用是否应导航到详细信息屏幕的逻辑:

// in the BLoC:
Stream<int> showContactDetail;

// in the UI layer:
bloc.showContactDetail.listen(_showContactDetail);

如何将参数传递到详细路由完全取决于您。您可以使用命名路由,但使用构建器传输数据会更容易:

void _showContactDetail(int contactId) {
  Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
    return ContactDetailPage(
      contactId: contactId,
    );
  }));
}

2) 一个 BLoC 应该绑定到单个屏幕,这意味着应该有一个单独的 BLoC 用于详细屏幕(或对话框/侧边栏/...),并且您可以将联系人的 id 传递给第二个屏幕BLoC 作为构造函数参数,或者使用StreamSink,或者使用简单的setter方法。

我建议您对 BLoC 输入使用普通的旧方法而不是 StreamSinks。 Here 是最近关于这个话题的讨论。


3) 问题不仅在于如何从详细信息屏幕更新您的联系人,还在于详细信息 BLoC 如何获取联系人数据(如果您只是传输联系人 ID)。

答案:另一个应用层,我称之为数据层,在所有 BLoC 之间共享。您可以将数据存储在 Firebase、sqlite 数据库或简单的 Map&lt;int, Contact&gt; 中。

数据层还将更改传播到后端,并在数据更改时通知所有 BLoC,可能使用Stream


接下来会出现的问题是您将这个数据层放在哪里(例如,一个名为 ContactService 的类):

  • 您可以在ContactListPage 中创建ContactService,然后在构造函数参数中将其传递给ContactDetailPage(使用路由构建器,如上所述)。这里没有魔法。您可能不希望出现的副作用是在弹出列表页面时该服务将被丢弃。
  • InheritedWidget 即在MaterialApp 之上,或者至少在MaterialApp 生成的Navigator 之上(您可以使用MaterialAppbuilder 来用您自己的小部件包装导航器)。将它放在树的高处可确保您应用的所有页面都可以访问它。
  • 使用scoped_model,基本一样。还必须插入到导航器上方才能从两条路线访问
  • 静态变量/单例

【讨论】:

    猜你喜欢
    • 2019-04-20
    • 2021-02-22
    • 2019-07-05
    • 2020-02-07
    • 2020-06-07
    • 2021-03-19
    • 2021-06-17
    • 2020-07-18
    • 2020-06-17
    相关资源
    最近更新 更多