BLoC 中的逻辑应该如何触发一次性 UI 警报,例如对话框或快餐栏?

Posted

技术标签:

【中文标题】BLoC 中的逻辑应该如何触发一次性 UI 警报,例如对话框或快餐栏?【英文标题】:How should logic in a BLoC trigger a one-time UI alert, like a dialog or snackbar? 【发布时间】:2020-05-16 10:34:36 【问题描述】:

当使用 BLoC 模式将业务逻辑与视图隔离时(没有 bloc library),当一些异步逻辑完成时,我们如何触发一次性 UI 调用(例如显示快餐​​栏或警报对话框)一个集团?例如,如果网络请求失败,我们希望显示一个对话框,通知用户无法获取某些数据。

我探索的选项是:

    在小部件的 build 方法中使用 StreamBuilder 来监听来自 bloc 的事件,并在 StreamBuilder 的 build 方法中显示对话框。这种方法的问题是StreamBuilderbuild 方法实际上不会在此处构建任何东西。我们只是要求 Flutter 显示一个对话框。我们可以返回一些不可见的“假”小部件只是为了让 Flutter 开心,但这真的很 hacky。

    使小部件有状态。在initState中,订阅来自BLoC的错误流,并在监听器中显示对话框。这里我们保持逻辑/视图的解耦,但据我所知,这个选项甚至没有可行,因为我们没有显示对话框所需的BuildContext

    当小部件调用 BLoC 上的某些逻辑可能会导致应触发对话框的更改时,传入显示对话框的回调。在此处列出的选项中,我更喜欢这个。逻辑和视图仍然是相当独立的,但感觉有点奇怪。 BLoC 模式中的数据流通常是纯粹的“widget -> BLoC via sinks or functions”和“BLoC -> widget via streams”。在某些逻辑执行后,让小部件要求 BLoC 调用回调(将数据传回)是违反此模式的。

我一直避免使用 bloc 库(为了保持简单,以及其他原因)。但是,它似乎确实以BlocListener 的形式提供了解决此问题的方法。有没有一种简单的方法可以在保持 BLoC 核心原则的同时解决这个问题?

【问题讨论】:

【参考方案1】:

我只是在解决这个确切的问题。这是我的解决方案 - 它属于第 2 类:

class CurrencyStreamListener extends StatefulWidget 
  final Stream<CurrencyNotification> notificationStream;
  final Widget child;
  CurrencyStreamListener(this.notificationStream, this.child);

  @override
  _CurrencyStreamListenerState createState() => _CurrencyStreamListenerState();


class _CurrencyStreamListenerState extends State<CurrencyStreamListener> 
  @override
  void initState() 
    widget.notificationStream.listen((CurrencyNotification data) 
      if (data is NotificationOfIncrease) 
        Scaffold.of(context).showSnackBar(
          SnackBar(
            duration: Duration(seconds: 1),
            content: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Earned Currency'),
              ],
            ),
          ),
        );
      
    );
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return widget.child;
  

这样我可以在任何可以访问 Bloc 流的地方嵌套这个小部件,所以可能在某个 Provider 或 Consumer 类下。

【讨论】:

【参考方案2】:

在进一步查看StatefulWidget 之后,我发现我们实际上确实可以访问initState 中的BuildContext context。因此,选项#2 毕竟是可行的。它允许我们保持逻辑和视图分离,并保持数据仅使用流从 BLoC 流向小部件的模式。

重申解决方案:BLoC 可以公开有状态小部件可以在StateinitState 中订阅的数据流(例如错误代码)。侦听器可以使用context 属性在流发出一些数据时显示对话框。

【讨论】:

【参考方案3】:

我所做的是:在我的 bloc 状态下,我有一个属性,其中包含一个可以为 null 的 Snackbar 对象。

如果我需要显示一些消息,我将其设置为一个值,否则,我将其设置为 null。

在我的 bloc 监听器中,我检查它是否不为空并显示它。

为了确保它只会被触发一次,我的 mapEventToState 中的第一行是产生一个新状态,其中 message 属性为空。

【讨论】:

以上是关于BLoC 中的逻辑应该如何触发一次性 UI 警报,例如对话框或快餐栏?的主要内容,如果未能解决你的问题,请参考以下文章

Azure 警报仅触发一次

如何知道我应该从 BLOC 或 Cubit 中选择啥

Flutter:bloc,如何显示警报对话框

mapEventToState 仅触发一次

flutter - bloc - 我如何在我的 Ui 中使用 FutureBuilder 来正确实现 Bloc 架构

每次触发警报时,连接到逻辑应用 Webhook 的 Azure 警报操作都会触发两次