Bloc、颤振和导航 [英] Bloc, Flutter and Navigation

查看:21
本文介绍了Bloc、颤振和导航的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以和大多数人一样,我是 Bloc 的新手,我会颤抖、飞镖和绕圈子.我用谷歌搜索过,查看了这里的帖子,但没有找到任何答案.

So like most, i'm new to Bloc and flutter and dart and wrapping my head around. I've googled, looked through the posts here but haven't found really any answers.

所以这是关于使用 bloc 和颤振的导航.以登录为例.所以有一个登录页面,后面有一个块,在某些时候有人按下按钮登录.

So this is about navigation with bloc and flutter. Take the example of a Login. So there is a login page with a bloc behind it and at some point someone presses a button to login.

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

So we can call a function in the bloc that does the validation. I think this is against the strict approach but i see people doing this. But then if login is successful how do you navigate to the next screen? You're not supposed to navigate in a bloc?

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

But if that login page is using a StreamBuilder to change state then you cannot add a navigate in a builder either can you? You can't return navigation, you return widgets.

initstate 是您可以导航的地方,但是您是否可以在 initstate 中有一个流构建器来侦听 bloc 中的状态变化?

The initstate is somewhere you could navigate, but can you have a stream builder in an initstate that listens for state changes in the bloc?

现在有点混乱,但我坚持,因为这是应该成为前进的方向......

It's all a little confusing right now but i'm persevering as this is supposed to be the way forward...

谢谢保罗

推荐答案

消除 BLoC 是 前进道路的神话:处理状态没有完美的方法.每个状态管理架构都比其他的更好地解决了一些问题;总有权衡取舍,在决定架构时了解它们很重要.

To get the myth of BLoC being the way forward right out of the way: There is no perfect way for handling state. Every state management architecture solves some problems better than others; there are always trade-offs and it's important to be aware of them when deciding on an architecture.

通常,好的架构是实用的:它具有可扩展性和可扩展性,同时只需要最少的开销.由于人们对实用性的看法不同,架构总是涉及到意见,所以下面我将就如何为您的应用采用 BLoC 阐述我个人的看法.

Generally, good architecture is practical: It's scalable and extensible while only requiring minimal overhead. Because people's views on practicability differ, architecture always involves opinion, so take the following with a grain of salt as I will lay out my personal view on how to adopt BLoC for your app.

BLoC 是 Fl​​utter 中一种非常有前途的状态管理方法,因为它有一个标志性成分:流.它们允许将 UI 与业务逻辑分离,并且它们与 Flutter-ish 的方法很好地配合,一旦它们过时就重建整个小部件子树.所以很自然,BLoC 之间的每次通信都应该使用流,对吗?

BLoC is a very promising approach for state management in Flutter because of one signature ingredient: streams. They allow for decoupling the UI from the business logic and they play well with the Flutter-ish approach of rebuilding entire widget subtrees once they're outdated. So naturally, every communication from and to the BLoC should use streams, right?

+----+  Stream   +------+
| UI | --------> | BLoC |
|    | <-------- |      |
+----+   Stream  +------+

嗯,有点.

要记住的重要一点是状态管理架构是达到目的的手段;你不应该只是为了它而做事,而是要保持开放的心态,仔细评估每个选项的利弊.我们将 BLoC 与 UI 分开的原因是 BLoC 不需要关心 UI 的结构——它只提供一些不错的简单流,而数据发生的任何事情都是 UI 的责任.

The important thing to remember is that state management architecture is a means to an end; you shouldn't just do stuff for the sake of it but keep an open mind and carefully evaluate the pros and cons of each option. The reason we separate the BLoC from the UI is that the BLoC doesn't need to care about how the UI is structured – it just provides some nice simple streams and whatever happens with the data is the UI's responsibility.

虽然流已被证明是一种将信息从 BLoC 传输到 UI 的绝妙方式,但它们在另一个方向上增加了不必要的开销:Streams 旨在传输连续的数据流(甚至在名称中也是如此),但大多数时候,UI 只需要触发 BLoC 中的单个事件.这就是为什么有时您会看到一些 Stream<void> 或类似的 hacky 解决方案¹,只是为了遵守严格的 BLoC-y 做事方式.

But while streams have proven to be a fantastic way of transporting information from the BLoC to the UI, they add unnecessary overhead in the other direction: Streams were designed to transport continuous streams of data (it's even in the name), but most of the time, the UI simply needs to trigger single events in the BLoC. That's why sometimes you see some Stream<void>s or similarly hacky solutions¹, just to adhere to the strictly BLoC-y way of doing things.

此外,如果我们要基于来自 BLoC 的流推送新路由,则 BLoC 基本上会控制 UI 流——但我们试图阻止的正是直接控制 UI 和业务逻辑的代码!

Also, if we would push new routes based on the stream from the BLoC, the BLoC would basically control the UI flow – but having code that directly controls both the UI and the business logic is the exact thing we tried to prevent!

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

That's why some developers (including me) just break with the entirely stream-based solution and adopt a custom way of triggering events in the BLoC from the UI. Personally, I simply use method calls (that usually return Futures) to trigger the BLoC's events:

+----+   method calls    +------+
| UI | ----------------> | BLoC |
|    | <---------------- |      |
+----+   Stream, Future  +------+

在这里,BLoC 返回 Streams 用于实时"数据,并返回 Futures 作为方法调用的答案.

Here, the BLoC returns Streams for data that is "live" and Futures as answers to method calls.

让我们看看这对您的示例有何影响:

Let's see how that could work out for your example:

  • BLoC 可以提供用户是否登录的 Stream,甚至可以提供 Stream,其中 Account 包含用户的帐户信息.
  • BLoC 还可以提供异步 Future;signIn(String username, String password) 方法,如果登录成功则不返回任何内容,否则抛出错误.
  • UI 可以自行处理输入管理,并在按下登录按钮后触发类似以下内容:
  • The BLoC could provide a Stream<bool> of whether the user is signed in, or even a Stream<Account>, where Account contains the user's account information.
  • The BLoC could also provide an asynchronous Future<void> signIn(String username, String password) method that returns nothing if the login was successful or throws an error otherwise.
  • The UI could handle the input management on its own and trigger something like the following once the login button is pressed:
try {
  setState(() => _isLoading = true); // This could display a loading spinner of sorts.
  await Bloc.of(context).signIn(_usernameController.text, _passwordController.text);
  Navigator.of(context).pushReplacement(...); // Push logged in screen.
} catch (e) {
  setState(() => _isLoading = false);
  // TODO: Display the error on the screen.
}

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

This way, you get a nice separation of concerns:

  • BLoC 确实只是在做它应该做的事情——处理业务逻辑(在本例中,是让用户登录).
  • 用户界面只关心两件事:
    • 显示来自 Stream
    • 的用户数据
    • 通过在 BLoC 中触发用户操作并根据结果执行 UI 操作来对用户操作做出反应.²

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

    Finally, I want to point out that this is only one possible solution that evolved over time by trying different ways of handling state in a complex app. It's important to get to know different points of view on how state management could work so I encourage you to dig deeper into that topic, perhaps by watching the "Pragmatic State Management in Flutter" session from Google I/O.

    编辑:刚刚在 Brian Egan 的架构示例中找到了这个架构,其中它被称为简单的 BLoC".如果你想了解不同的架构,我真的建议你看看 repo.

    EDIT: Just found this architecture in Brian Egan's architecture samples, where it's called "Simple BLoC". If you want to get to know different architectures, I really recommend having a look at the repo.

    ¹当尝试为 BLoC 操作提供多个参数时,它变得更加丑陋 - 因为你需要定义一个包装类,只是为了将它传递给 Stream.

    ¹ It gets even uglier when trying to provide multiple arguments to a BLoC action – because then you'd need to define a wrapper class just to pass that to the Stream.

    ² 我确实承认在启动应用程序时它有点难看:您需要某种启动屏幕来检查 BLoC 的流并根据以下内容将用户重定向到适当的屏幕无论他们是否登录.发生该规则的异常是因为用户执行了一个操作——启动应用程序——但 Flutter 框架并不允许我们直接挂钩(据我所知,至少不是很优雅).

    ² I do admit it gets a little bit ugly when starting the app: You'll need some sort of splash screen that just checks the BLoC's stream and redirects the user to the appropriate screen based on whether they signed in or not. That exception to the rule occurs because the user performed an action – starting the app – but the Flutter framework doesn't directly allow us to hook into that (at least not elegantly, as far as I know).

    这篇关于Bloc、颤振和导航的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆