状态机 简化

    科技2022-07-12  160

    状态机 简化

    If you’ve been developing Flutter apps, you know it’s crucial to manage the state of your application in the best possible way.

    如果您一直在开发Flutter应用程序,那么就知道以最佳方式管理应用程序状态至关重要。

    Flutter provides us with many state-management options, like Provider, Bloc, Redux, and MobX.

    Flutter为我们提供了许多状态管理选项,例如Provider,Bloc,Redux和MobX。

    Today, we’ll look at Bloc.

    今天,我们来看一下Bloc。

    I understand it can be a little harder to understand — it was for me as well. But now I think I get it, so I’m here to simplify it for you.

    我知道很难理解,这对我来说也是如此。 但是现在我想我明白了,所以我在这里为您简化一下。

    We know that in Flutter it's very easy to mix up your UI logic with your business logic, which isn’t really the best way to develop maintainable apps.

    我们知道,在Flutter中,很容易将UI逻辑与业务逻辑混合在一起,这并不是开发可维护应用程序的最佳方法。

    Bloc comes to the rescue by giving a better structure to your app — by separating out the UI and the business logic of your application. But before we get into how to implement it, let’s first understand …

    Bloc通过为您的应用程序提供更好的结构来解决问题-通过分离UI和应用程序的业务逻辑。 但是,在我们开始实施它之前,让我们先了解一下……

    The article’s going to be a little long, but you, as a beginner, will walk away with the confidence of how to use Bloc by the end.

    这篇文章将要花一些时间,但是作为一个初学者,您将对如何最终使用Bloc充满信心。

    反正是什么集团 ? (What’s Bloc Anyway?)

    Bloc stands for business logic and component. It's like a black box that wraps up all your business logic (and related components) and maps various app events to app states.

    Bloc代表业务逻辑和组件。 就像黑盒子一样,它包装了您所有的业务逻辑(和相关组件),并将各种应用程序事件映射到应用程序状态。

    If that definition was a little too technical for you, let’s try to understand it better with a few examples.

    如果该定义对您来说太技术性了,让我们尝试通过一些示例更好地理解它。

    如果您使用的是天气应用: (If your‘e using a weather app:)

    There will be various events in your app, like getWeather() setLocation(), and resetWeather() that’lll be triggered upon user actions or some internal logic of your app.

    您的应用中将发生各种事件,例如getWeather() setLocation() , 和resetWeather()它们将在用户操作或应用程序的某些内部逻辑时触发。

    These actions will then update your app’s UI with a new state accordingly after the operation is performed successfully.

    这些操作将在成功执行操作之后相应地以新状态更新应用的UI。

    另一个示例-默认的Flutter计数器应用 (Another example — the default Flutter counter app)

    There’s only one event here, and that’s incrementCounter, which generates the new state, showing the incremented value of the counter.

    这里只有一个事件,那就是incrementCounter计数器( incrementCounter ,它生成新状态,显示计数器的增量值。

    bloc is the black box that’ll tell you which operation should be performed on which event and then which state should be generated after the operation completes.

    bloc是黑框,告诉您应该在哪个事件上执行哪个操作,然后告诉您操作完成后应该生成哪个状态。

    如何为您的应用程序定义Bloc? (How Do You Define Bloc for Your Application?)

    付出的代价很小 (There’s a small price to pay)

    A major drawback of Bloc is the amount of boilerplate code we have to write — even just for smallest of UI changes.

    Bloc的一个主要缺点是我们必须编写大量的样板代码,即使是最小的UI更改也是如此。

    That’s the only drawback I’ve seen so far, but it certainly simplifies your app’s code by separating out all the UI logic from the business logic.

    到目前为止,这是我唯一看到的缺点,但是通过将所有UI逻辑与业务逻辑分离开来,肯定可以简化应用程序的代码。

    So you can take all the boilerplate code as an investment required to keep your code easy to maintain and understand with Bloc.

    因此,您可以将所有样板代码作为一项投资,以使您的代码易于维护和理解。

    这就是你得到的 (Here’s what you get)

    For example, say you’re building a weather application using Bloc. You’ve defined all of your events and states, and your app is working perfectly.

    例如,假设您正在使用Bloc构建天气应用程序。 您已经定义了所有事件和状态,并且您的应用程序运行正常。

    Now if you have to add another feature within the same screen, you can very simply go ahead and define a new event and a new state inside your bloc with a small bit of logic on how to map the new event to a new state.

    现在,如果你要在同一屏幕中添加其他功能,你可以很简单地去前进,你的定义里面一个新的事件和新的国家bloc与逻辑上如何将新的事件映射到一个新的状态小一点。

    You’re done! You don’t have touch/disturb other built events and states, and you can very simply add your new set of features without much of a problem.

    你完成了! 您无需触摸/打扰其他已建立的事件和状态,并且可以非常简单地添加新功能集,而不会出现很多问题。

    This is similar to what the open-closed principle of the SOLID principles tells you to do.

    这类似于SOLID原理的开闭原理告诉您的操作。

    我们将要建设的 (What We’ll Be Building)

    We’ll be building a modified version of the counter app, which will help you get a clearer picture of bloc.

    我们将构建计数器应用程序的修改版本,这将帮助您更清晰地了解bloc 。

    There will be four buttons:

    将有四个按钮:

    Increment counter value: Instantly updates counter value

    递增计数器值:立即更新计数器值

    Decrement counter value: Instantly updates counter value

    递减计数器值:立即更新计数器值

    Generate random value: We’ll simulate some delay and then update the value

    生成随机值:我们将模拟一些延迟,然后更新该值

    If you understood the requirements, you can see the what we’ve bolded above are events, and the explanation to the right of the colon are the states.

    如果您理解了这些要求,那么可以看到上面我们用粗体显示的是事件,而冒号右边的解释是状态。

    1.将这些依赖项添加到您的pubspec.yaml中 (1. Add These Dependencies to Your pubspec.yaml)

    As of March 2020, I’m adding this dependency for Flutter.

    从2020年3月开始,我为Flutter添加了这种依赖关系。

    flutter_bloc: ^3.2.0equatable: ^1.1.0

    bloc is the library created by the bloclibrary.dev team, and it provides the core fundamentals of the bloc pattern. But it’s a little bit more complex — hence, we get flutter_bloc, created by the same team just to make things easy for Flutter devs.

    bloc是bloclibrary.dev团队创建的库,它提供了bloc模式的核心基础。 但这有点复杂-因此,我们得到了flutter_bloc ,它是由同一团队创建的,只是为了使Flutter开发人员更轻松。

    Thank you team!

    谢谢团队!

    2.创建您的“ Bloc”类 (2. Create Your ‘Bloc’ Class)

    My UI code will be in the CounterScreen inside the counter_screen.dart file. (We’ll get to the UI part later.)

    我的UI代码将位于counter_screen.dart文件内的CounterScreen 。 (我们将在稍后进入UI部分。)

    Create a new Dart file for your bloc class with the name counter_screen_bloc.dart. We’ll define this bloc class file.

    为您的bloc类创建一个新的Dart文件,名称为counter_screen_bloc.dart 。 我们将定义此bloc类文件。

    Inside the bloc screen, we’ll define three things:

    在bloc屏幕中,我们将定义三件事:

    Event: To show all possible events

    事件:显示所有可能的事件

    State: To show all possible states

    状态:显示所有可能的状态

    Bloc: How to map those events to states

    团体:如何将这些事件映射到州

    These are the import statements required for the next steps.

    这些是下一步所需的导入语句。

    import 'package:bloc/bloc.dart';import 'package:equatable/equatable.dart';

    3.定义事件 (3. Define Events)

    Inside the blank bloc class file, start with defining an event.

    在空白的bloc类文件中,从定义事件开始。

    I’ve named it CounterScreenEvent.

    我将其命名为CounterScreenEvent 。

    Equatable makes our classes equatable/comparable, which is required for the mapping logic inside the bloc class.

    Equatable使我们的类成为Equatable / comparable,这是bloc类内部的映射逻辑所必需的。

    Equatable asks you to override the get props like we’ve done here.

    Equatable要求您像我们在此处所做的那样覆盖get props 。

    4.定义状态 (4. Define States)

    Below these, let’s define the states that each of these will be mapped to.

    在这些下面,让我们定义每个状态都将映射到的状态。

    为什么只有两个状态? (Why, just two states?)

    Well either the user will see the incremented/decremented counter values on the screen, or they’ll see a loading screen while we’re trying to generate a random number simulating a network call.

    嗯,或者用户将在屏幕上看到递增/递减的计数器值,或者在我们尝试生成模拟网络呼叫的随机数时,他们将看到加载屏幕。

    The ShowCounterValue state will have a counter value associated with it. Hence, we define a property in that class called counterValue to help you pass the counter value to the UI of the application from Bloc.

    ShowCounterValue状态将具有与其关联的计数器值。 因此,我们在该类中定义了一个名为counterValue的属性,以帮助您将计数器值从Bloc传递到应用程序的UI。

    5.最后,定义我们的“集团” (5. Finally, Define Our ‘Bloc’)

    Yeah, we finally can define our bloc.

    是的,我们终于可以定义我们的bloc 。

    /// BLoCclass DashboardScreenBLoC extends Bloc<CounterScreenEvent, CounterScreenState> { int counterValue = 0;@override CounterScreenState get initialState => ShowCounterValue(counterValue); @override Stream<CounterScreenState> mapEventToState(CounterScreenEvent event) async* { // TODO : Map event to state}}

    In the first line, we have DashboardScreenBloc, which extends Bloc<Event,State> as we have defined above

    在第一行中,我们有DashboardScreenBloc ,它扩展了如上定义的Bloc<Event,State>

    We define a property for our counter value called counterValue, which will be used to maintain the state of our counter

    我们为计数器值定义一个属性counterValue ,该属性将用于维护计数器的状态

    Now we have to define initialState. When the bloc loads, the initial state will be set to ShowCounterValue(counterValue).

    现在我们必须定义initialState 。 当bloc加载时,初始状态将设置为ShowCounterValue(counterValue) 。

    Finally, we have a mapEventToState function (which does exactly as the name signifies). If you take a look at the function, you’ll see it’s marked as async*.

    最后,我们有一个mapEventToState函数(其功能与名称所指完全相同)。 如果您看一下该函数,就会看到它被标记为async* 。

    Just to keep everyone on the same page, I’m going to explain async vs async*.

    为了让所有人都在同一页面上,我将解释async vs async* 。

    If your function returns a future value after performing a certain operation, we mark that function as async. These functions return a value only once, and their execution ends with the return statement.

    如果您的函数在执行某些操作后返回了将来的值,则我们将该函数标记为async 。 这些函数仅返回一次值,并且其执行以return语句结束。

    The function marked as async*, on the other hand, returns a stream. This function yields different values and doesn’t just return them back. Their execution still continues, and they can yield as many values as you want.

    另一方面,标记为async*的函数返回流。 此函数产生不同的值,而不仅仅是返回它们。 它们的执行仍在继续,并且它们可以产生所需数量的值。

    That’s why their output is called a stream.

    这就是为什么它们的输出称为流。

    Let’s finish our bloc by mapping events to states.

    让我们通过将事件映射到状态来结束我们的bloc 。

    Below is the full counter_screen_bloc.dart code.

    以下是完整的counter_screen_bloc.dart代码。

    Important Thing To Know

    An important thing to know about bloc is if nextState == currentState evaluates to true, bloc ignores the state transition.

    关于bloc的重要一件事是,如果nextState == currentState计算结果为true ,则bloc忽略状态转换。

    If you don’t extend your state class as Equatable, all of the states that you’ll be calling from yield will be treated as unique.

    如果您不将状态类扩展为Equatable ,那么将从yield调用的所有状态都将被视为唯一。

    If that fits your requirements, you shouldn’t bother much, but if there’s a chance there will be states repeated one after the other, why waste your performance on rebuilding the same state?

    如果这符合您的要求,您就不必费心,但是如果有机会将状态一遍又一遍地重复,为什么要浪费您的性能来重建相同的状态?

    Hence, we extend Equatable and override the props method.

    因此,我们扩展了Equatable并覆盖了props方法。

    class ShowCounterValue extends CounterScreenState { @override List<Object> get props => [counterValue]; final int counterValue; ShowCounterValue(this.counterValue);}

    If you don’t override the props method, your bloc won’t know how to compare the two state classes and will probably treat them the same. Hence, you wouldn’t see the new state being triggered.

    如果您不重写props方法,您的bloc将不知道如何比较两个状态类,并且可能将它们视为相同。 因此,您不会看到新状态被触发。

    6.让我们在那个UI上工作 (6. Let’s Work on That UI)

    从main.dart开始 (Starting with main.dart)

    Since we’re using a bloc named CounterScreenBloc in our UI named CounterScreen, we use a BlocProvider and we define what has to be provided with which bloc.

    因为我们使用了一个bloc叫CounterScreenBloc我们命名UI CounterScreen ,我们使用BlocProvider ,我们定义什么必须提供与bloc 。

    Here is the full main.dart code.

    这是完整的main.dart代码。

    让我们看一下 'counter_screen.dart' (Let’s look inside 'counter_screen.dart’)

    Inside the build function of our CounterScreen, we have to initialise the bloc. Similarly, inside the dispose function, we have to close our bloc to avoid memory leaks.

    在CounterScreen的build函数内部,我们必须初始化bloc 。 同样,在dispose函数内部,我们必须关闭我们的bloc以避免内存泄漏。

    It's a good practice to dispose the bloc in the dispose() function of the same widget whose build() you may have used to initialize the bloc.

    Here’s the full counter_screen.dart :

    这是完整的counter_screen.dart :

    That’s it! You should have a functioning project.

    而已! 您应该有一个正常运行的项目。

    Here’s the code to the full project:

    这是整个项目的代码:

    结论 (Conclusion)

    That’s it! That’s all you have to know to go and build a kick-ass Flutter app with clean code — all thanks to Bloc.

    而已! 这就是您要知道的一切,并且使用干净的代码来构建一个Flutter应用程序,这一切都要感谢Bloc。

    Again, the boilerplate code you see is an investment in keeping your code maintainable.

    同样,您看到的样板代码是保持代码可维护性的投资。

    Also because of this, I wouldn’t recommend you apply it in all screens — only where there are a lot of different states involved.

    也正因为如此,我不建议您在所有屏幕上都应用它-仅在涉及许多不同状态的地方。

    Otherwise, Provider is another great state-management solution for simpler features in your application.

    否则, Provider是用于应用程序中更简单功能的另一个出色的状态管理解决方案。

    翻译自: https://medium.com/better-programming/simplifying-bloc-state-management-in-flutter-a8de43a994e4

    状态机 简化

    Processed: 0.010, SQL: 8