团体,颤动和导航

pau*_*ome 17 navigation flutter bloc

因此,像大多数人一样,我是Bloc的新手,挥舞着飞镖,将我的头缠住。我已经用Google搜索过,浏览了这里的帖子,但没有找到真正的答案。

所以这是关于用团块和颤动进行导航的。以登录为例。因此,有一个登录页面,后面有一个集团,有时有人按下按钮进行登录。

因此,我们可以在集团中调用一个函数进行验证。我认为这违反严格的方法,但我看到有人这样做。但是,如果登录成功,您如何导航到下一个屏幕?您不应该在一个集团中导航吗?

但是,如果该登录页面正在使用StreamBuilder更改状态,那么您也不能在构建器中添加导航,可以吗?您无法返回导航,而是返回小部件。

您可以在initstate中导航,但是在initstate中可以有一个流构建器来侦听整个组中的状态变化吗?

现在这有点令人困惑,但是我很坚持,因为这应该是前进的方向...

谢谢保罗

34m*_*4m0 14

BlocListener是您可能需要的小部件。如果状态更改为 (例如) LoginSuccess,则块侦听器可以调用通常的Navigate.of(context). 您可以在本页底部附近找到一个正在运行的示例BlocListener

另一种选择是将回调传递给事件。

 BlocProvider.of<MyBloc>(context).add(MyEvent(
              data: data,
              onSuccess: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) {
                    return HomePage();
                  }),
                );
              }));
Run Code Online (Sandbox Code Playgroud)


Mar*_*cel 13

为了让集团成为神话前进方向正确的方式进行:对于处理状态不完美的方式。每种状态管理体系结构都比其他解决方案更好地解决了一些问题。总会有一些权衡取舍,因此在决定架构时要意识到这一点很重要。

通常,良好的体系结构是可行的:它具有可伸缩性和可扩展性,而只需要最小的开销。由于人们对实用性的观点各不相同,因此架构始终会涉及各种观点,因此请仔细考虑以下内容,因为我将就如何为您的应用程序采用BLoC提出自己的看法。

BLoC是Flutter中非常有前途的状态管理方法,因为它具有一个标志性成分:流。它们允许将UI与业务逻辑分离,并且它们与Flutter-ish方法配合得很好,一旦过时,它们便可以重建整个小部件子树。因此,很自然,往返于BLoC的每个通信都应使用流,对吗?

+----+  Stream   +------+
| UI | --------> | BLoC |
|    | <-------- |      |
+----+   Stream  +------+
Run Code Online (Sandbox Code Playgroud)

好吧,有点。

要记住的重要一点是,状态管理体系结构是达到目的的一种手段;您不应该只是为了做到这一点而做事,而是要保持开放的态度并仔细评估每种选择的利弊。我们将BLoC与UI分开的原因是,BLoC不需要关心UI的结构-它仅提供一些不错的简单流,而数据发生的一切都是UI的责任。

但是,尽管流已被证明是从BLoC到UI传输信息的一种绝妙方式,但它们却在另一个方向上增加了不必要的开销:流被设计为传输连续的数据流(甚至是名称),但是大多数时间,UI只需要触发BLoC中的单个事件。这就是为什么有时您会看到某些Stream<void>或类似的恶意解决方案¹,只是为了遵循严格的BLoC-y处理方式。

另外,如果我们将基于来自BLoC的流推送新路由,则BLoC基本上将控制UI流程-但是我们试图避免的是拥有直接控制UI和业务逻辑的代码!

这就是为什么一些开发人员(包括我)只是打破了完全基于流的解决方案,并采用自定义方式从UI触发BLoC中的事件的原因。就个人而言,我只是使用方法调用(通常返回Futures)来触发BLoC的事件:

+----+   method calls    +------+
| UI | ----------------> | BLoC |
|    | <---------------- |      |
+----+   Stream, Future  +------+
Run Code Online (Sandbox Code Playgroud)

在这里,BLoC返回Streams表示“实时”数据,并返回Futures作为方法调用的答案。

让我们来看看如何为您的示例工作:

  • 该集团可以提供Stream<bool>的用户是否登录,甚至Stream<Account>,其中Account包含了用户的帐户信息。
  • BLoC还可以提供一种异步Future<void> signIn(String username, String password)方法,如果登录成功,该方法将不返回任何内容,否则将引发错误。
  • UI可以自行处理输入管理,并在按下登录按钮后触发类似以下的操作:
+----+  Stream   +------+
| UI | --------> | BLoC |
|    | <-------- |      |
+----+   Stream  +------+
Run Code Online (Sandbox Code Playgroud)

这样,您就可以很好地分离关注点:

  • BLoC实际上只是按照预期的方式工作-处理业务逻辑(在这种情况下,请登录用户)。
  • UI只关心两件事:
    • 显示来自Stream和的用户数据
    • 通过在BLoC中触发用户操作并根据结果执行UI操作来对用户操作做出反应。²

最后,我想指出的是,这只是一种可能的解决方案,它通过尝试在复杂应用程序中处理状态的不同方式随着时间而发展。重要的是要了解状态管理如何工作的不同观点,因此我鼓励您更深入地研究该主题,也许是通过观看Google I / O 的“实用的Flutter状态管理”会议。

编辑:刚刚在Brian Egan的体系结构样本中发现了此体系结构,在该示例中将其称为“简单BLoC”。如果您想了解不同的体系结构,我真的建议您看一下该仓库。


¹当尝试为BLoC动作提供多个参数时,它变得更加难看–因为您需要定义一个包装器类,才能将其传递给Stream。

²我确实承认启动应用程序时它会变得有些丑陋:您将需要某种启动屏幕,该启动屏幕仅检查BLoC的流,并根据用户是否登录将用户重定向到适当的屏幕。发生该规则异常是因为用户执行了一个操作(启动应用程序),但是Flutter框架不允许我们直接参与(据我所知,至少不是很优雅)。

  • 你的 BL 被分成 Bloc 和Presentation(这是不好的行为)。在您的示例中,您使用 setState 来处理演示文稿中的加载。 (2认同)

Vol*_*kiv 6

首先:如果没有业务逻辑,则无需转到 YourBloc 类。

但有时某些用户的活动需要在Bloc类中执行某些逻辑,然后 Bloc 类必须决定下一步做什么:只是重建小部件显示对话框,甚至导航到下一个路线。在这种情况下,您必须向 UI 发送一些状态才能完成操作。那么另一个问题出现了:当 Bloc 发送 State 来显示 toast 时,我该如何处理 widget?

这是整个故事的主要问题。

很多答案和文章推荐使用flutter_block。该库有BlocBuilderBlocListener。通过这些课程,您可以解决一些问题,但不能 100% 解决。

就我而言,我使用BlocConsumer来管理BlocBuilderBlocListener并提供管理状态的绝妙方法。

从文档中:

BlocConsumer<BlocA, BlocAState>(
  listenWhen: (previous, current) {
    // return true/false to determine whether or not
    // to invoke listener with state
  },
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  buildWhen: (previous, current) {
    // return true/false to determine whether or not
    // to rebuild the widget with state
  },
  builder: (context, state) {
    // return widget here based on BlocA's state
  }
)
Run Code Online (Sandbox Code Playgroud)

正如您在BlocConsumer中看到的,您可以过滤状态:您可以轻松定义状态来重建小部件和状态以显示一些弹出窗口或导航到下一个屏幕。


Ach*_*uru 5

正如 felangel 在下Github 中提到的,我们可以为此使用 BlocListner。

BlocListener(
    bloc: BlocProvider.of<DataBloc>(context),
    listener: (BuildContext context, DataState state) {
        if (state is Success) {              
            Navigator.of(context).pushNamed('/details');
        }              
    },
    child: BlocBuilder(
        bloc: BlocProvider.of<DataBloc>(context),
        builder: (BuildContext context, DataState state) {        
            if (state is Initial) {
                return Text('Press the Button');
            }
            if (state is Loading) {
                return CircularProgressIndicator();
            }  
            if (state is Success) {
                return Text('Success');
            }  
            if (state is Failure) {
                return Text('Failure');
            }
        },
    }
)
Run Code Online (Sandbox Code Playgroud)

  • 如果我返回并再次按按钮转到详细信息,但块抛出相同的状态“成功”(只是假设),侦听器不会触发任何 PushNamed,因为与以前的状态相同,我该如何处理那? (8认同)