flutter bloc

Last year, I picked up Flutter and I must say it has been an awesome journey so far. Flutter is Google’s awesome framework for crafting high-quality applications for Android and iOS.

去年,我接了Flutter ,我必须说到目前为止,这是一段了不起的旅程。 Flutter是Google出色的框架,可为Android和iOS制作高质量的应用程序。

As with building almost any application, there’s always the need to handle application state. It is important that state management is handled efficiently, so as to avoid accruing technical debt, especially as your application grows and becomes more complex.

与构建几乎所有应用程序一样,始终需要处理应用程序状态。 重要的是要有效地处理状态管理,以避免产生技术负担,尤其是随着应用程序的增长和变得越来越复杂。

In Flutter, all UI components are widgets. As you start composing these widgets to create your awesome app, you’ll end up with a tree of deeply nested widgets. These widgets will most likely need to share application state with each other.

在Flutter中,所有UI组件都是小部件。 在开始组合这些小部件以创建出色的应用程序时,最终将得到一棵嵌套极深的小部件树。 这些小部件很可能需要彼此共享应用程序状态。

In this article, we’ll see how to handle state in Flutter using the BLoC pattern.

在本文中,我们将看到如何使用BLoC模式处理Flutter中的状态。

State management in Flutter can be achieved in a few different ways:

Flutter中的状态管理可以通过几种不同的方式来实现:

Inherited Widget: It allows you propagate data to its child widgets and the widgets are rebuilt whenever there is a change in the app’s state. The downside of using the InheritedWidget base class is that your state is final and this raises a problem if you want to mutate your state.

继承的窗口小部件 :它允许您将数据传播到其子窗口小部件,并且只要应用程序状态发生变化,就可以重新构建窗口小部件。 使用InheritedWidget基类的不利之处在于您的状态是最终状态,如果您要更改状态,则会产生问题。

Scoped Model: This is an external package built on top of InheritedWidget and it offers a slightly better way to access, update and mutate state. It allows you to easily pass a data Model from a parent Widget down to its descendants. In addition, it also rebuilds all of the children that use the model when the model is updated.

范围模型 :这是一个在InheritedWidget之上构建的外部软件包,它提供了一种更好的访问,更新和变异状态的方法。 它使您可以轻松地将数据模型从父Widget传递到其后代。 此外,更新模型时,它还会重建使用该模型的所有子代。

This might raise a performance issue, depending on how many ScopedModelDescendants a model has, as they’re rebuilt when there’s an update.

这可能会导致性能问题,具体取决于模型具有多少ScopedModelDescendant,因为在进行更新时会重新构建它们。

This issue can be fixed by decomposing the ScopedModel into multiple models so you get finer-grained dependencies. Setting the rebuildOnChange flag to false also fixes this issue, but it brings with it the cognitive load of deciding what widget should be rebuilt or not.

可以通过将ScopedModel分解为多个模型来解决此问题,以便获得更细粒度的依赖关系。 将rebuildOnChange标志设置为false也可以解决此问题,但是它带来了决定是否应重建哪个小部件的认知负担。

Redux: Yes! As with React, there is a Redux package that helps you easily create and consume a Redux store in Flutter. Like its JavaScript counterpart, there’s usually a few lines of boilerplate code and the round trip of actions and reducers.

Redux :是的! 与React一样,有一个Redux软件包,可以帮助您轻松地在Flutter中创建和使用Redux存储。 与其JavaScript对应语言一样,通常会有几行样板代码以及actionreducers的往返行程。

输入BLoC模式 (Enter BLoC pattern)

The Business Logic Component (BLoC) pattern is a pattern created by Google and announced at Google I/O ’18. The BLoC pattern uses Reactive Programming to handle the flow of data within an app.

业务逻辑组件(BLoC)模式是由Google创建并在Google I / O '18上宣布的模式。 BLoC模式使用响应式编程来处理应用程序内的数据流。

A BLoC stands as a middleman between a source of data in your app (e.g an API response) and widgets that need the data. It receives streams of events/data from the source, handles any required business logic and publishes streams of data changes to widgets that are interested in them.

BLoC充当您应用程序中的数据源(例如API响应)与需要数据的小部件之间的中间人。 它从源接收事件/数据流,处理所有必需的业务逻辑,并将数据更改流发布到对其感兴趣的小部件。

A BLoC has two simple components: Sinks and Streams, both of which are provided by a StreamController. You add streams of event/data input into a Sink and listen to them as streams of data output through a Stream.

BLoC具有两个简单的组件: 接收器 ,这两个都由StreamController提供。 您将事件/数据输入流添加到接收器中 ,并作为通过Stream输出的数据流来侦听它们。

A StreamController can be accessed via the ‘dart:async’ library or as a PublishSubject, ReplaySubject or BehaviourSubject via the rxdart package.

可以通过'dart:async'库访问StreamController,也可以通过rxdart包将其作为PublishSubjectReplaySubjectBehaviourSubject进行rxdart

Below is a code snippet showing a simple BLoC:

以下是显示简单BLoC的代码段:

import 'dart:async';
// import 'package:rxdart/rxdart.dart'; if you want to make use of PublishSubject, ReplaySubject or BehaviourSubject.
// make sure you have rxdart: as a dependency in your pubspec.yaml file to use the above import


class CounterBloc {
  final counterController = StreamController();  // create a StreamController or
  // final counterController = PublishSubject() or any other rxdart option;
  Stream get getCount => counterController.stream; // create a getter for our Stream
  // the rxdart stream controllers returns an Observable instead of a Stream
  
  void updateCount() {
    counterController.sink.add(data); // add whatever data we want into the Sink
  }
  
  void dispose() {
    counterController.close(); // close our StreamController to avoid memory leak
  }
}

final bloc = CounterBloc(); // create an instance of the counter bloc

//======= end of CounterBloc file



//======= somewhere else in our app
import 'counter_bloc.dart'; // import the counter bloc file here

@override
void dispose() {
  bloc.dispose(); // call the dispose method to close our StreamController
  super.dispose();
}

...
@override
Widget build(BuildContext context) {
  return StreamBuilder( // Wrap our widget with a StreamBuilder
    stream: bloc.getCount, // pass our Stream getter here
    initialData: 0, // provide an initial data
    builder: (context, snapshot) => Text('${snapshot.data}'), // access the data in our Stream here
  );
}
...

A BLoC is a simple Dart class. In the code snippet above, we created a CounterBloc class and in it, a StreamController which we called counterController. We created a getter for our Stream called getCount, an updateCount method that adds data into our Sink when called, and a dispose method to close our StreamController.

BLoC是简单的Dart类。 在上面的代码片段中,我们创建了一个CounterBloc类,并在其中创建了一个StreamController ,我们将其称为counterController 。 我们为流创建了一个名为getCountgetter ,一个updateCount方法在调用时将数据添加到接收器中,还有一个dispose方法来关闭StreamController。

To access the data in our Stream, we created a StreamBuilder widget and passed our Stream to its stream property and accessed the data in its builder function.

为了访问Stream中的数据,我们创建了一个StreamBuilder小部件,并将Stream传递到其stream属性,并在其builder函数中访问了数据。

实施BLoC (Implementing BLoC)

We’ll be converting the default Flutter sample app to use a BLoC. Let’s go ahead and generate a new Flutter app. In your terminal run the following command:

我们将转换默认的Flutter示例应用程序以使用BLoC。 让我们继续并生成一个新的Flutter应用。 在您的终端中运行以下命令:

$ flutter create bloc_counter && cd bloc_counter

Open the app in your favourite editor and create three files in the lib folder: counter.dart, counter_provider.dart and counter_bloc.dart.

在您喜欢的编辑器中打开应用程序,然后在lib文件夹中创建三个文件: counter.dartcounter_provider.dartcounter_bloc.dart

Our CounterProvider will contain an integer and a method to increment it. Add the following code to the counter_provider.dart file:

我们的CounterProvider将包含一个整数和一个递增它的方法。 将以下代码添加到counter_provider.dart文件中:

class CounterProvider {
  int count = 0;
  void increaseCount() => count++;
}

Next, we’ll implement our counter BLoC. Add the code below into your counter_block.dart file:

接下来,我们将实现计数器BLoC。 将以下代码添加到您的counter_block.dart文件中:

In our CounterBloc class, we used part of our initial sample code above. On line 7, we instantiated our CounterProvider class and in the updateCount method, we called the provider method to increment the count, and then on line 13, we passed the count to our Sink.

CounterBloc类中,我们使用了上面的部分初始示例代码。 在第7行,我们实例化了CounterProvider类,在updateCount方法中,我们调用了provider方法来增加计数,然后在第13行,将计数传递给Sink。

Replace the code in your main.dart file with the code below. In the code below, we simply removed most of the default counter code, which we’ll move to our counter.dart file. Whenever the incrementCounter method is called, we call the BLoC ‘s updateCount method which updates the count and adds it to our Sink.

用下面的代码替换main.dart文件中的代码。 在下面的代码中,我们仅删除了大多数默认计数器代码,这些代码将移至counter.dart文件。 每当调用incrementCounter计数器方法时,我们都会调用BLoC的updateCount方法,该方法将更新计数并将其添加到接收器中。

Now, our BLoC is receiving and streaming data. We can access that data and display it on a screen through a StreamBuilder. We wrap whatever widget that needs the data in a StreamBuilder widget and pass the stream containing the data to it. Add the following code to the counter.dart file:

现在,我们的BLoC正在接收和流式传输数据。 我们可以访问该数据,并通过StreamBuilder将其显示在屏幕上。 我们将需要数据的所有小部件包装在StreamBuilder小部件中,并将包含数据的流传递给它。 将以下代码添加到counter.dart文件:

In the code above, we have a stateful widget. In our state class, on line 13, we call our bloc’s dispose method, so that stream controller can be closed whenever the widget is removed from the tree.

在上面的代码中,我们有一个有状态的小部件。 在第13行的状态类中,我们调用了块的dispose方法,这样,只要将控件从树中移除,就可以关闭流控制器。

On line 19, we return a StreamBuilder widget and line 20, we pass the getter for our stream to it and also an initial data on line 21. The StreamBuilder also has a builder which gives us access to the data via a snapshot. On line 30, we access and display the data in the snapshot.

在第19行,我们返回StreamBuilder小部件,在第20行,我们将流的吸气剂传递给它,并在第21行传递初始数据。StreamBuilder还具有一个生成builder ,使我们可以通过snapshot访问数据。 在第30行,我们访问并显示快照中的数据。

Go ahead and run the app by running the command below. Ensure you have an emulator running.

继续并通过运行以下命令来运行该应用程序。 确保您正在运行模拟器。

$ flutter run

With your app running, click the plus icon and watch the counter increase with every click.

在您的应用程序运行的情况下,单击加号图标,然后观察计数器随着每次单击而增加。

Together, we’ve been able to implement the simplest form of a BLoC in Flutter. The concept remains the same regardless of your use case.

总之,我们已经能够在Flutter中实现最简单的BLoC形式。 无论使用哪种情况,概念都保持不变。

I hope you found this article useful. Please do and share so others can find this article. Hit me up on Twitter @developia_ with questions or for a chat.

希望本文对您有所帮助。 请分享,以便其他人可以找到本文。 通过问题或聊天在Twitter @d evelopia_上打我。

翻译自: https://www.freecodecamp.org/news/how-to-handle-state-in-flutter-using-the-bloc-pattern-8ed2f1e49a13/

flutter bloc

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐