BLoCパターンを使用してFlutterで状態を処理する方法

昨年、私はFlutterを手に入れましたが、これまでのところ素晴らしい旅だったと言わざるを得ません。Flutterは、AndroidおよびiOS向けの高品質アプリケーションを作成するためのGoogleの優れたフレームワークです。

ほとんどすべてのアプリケーションを構築する場合と同様に、アプリケーションの状態を処理する必要が常にあります。特にアプリケーションが成長し、より複雑になるにつれて、技術的負債が発生しないように、状態管理を効率的に処理することが重要です。

Flutterでは、すべてのUIコンポーネントはウィジェットです。これらのウィジェットを作成して素晴らしいアプリを作成し始めると、深くネストされたウィジェットのツリーができあがります。これらのウィジェットは、ほとんどの場合、アプリケーションの状態を相互に共有する必要があります。

この記事では、BLoCパターンを使用してFlutterで状態を処理する方法を説明します。

Flutterの状態管理は、いくつかの異なる方法で実現できます。

継承されたウィジェット:データを子ウィジェットに伝播でき、アプリの状態が変更されるたびにウィジェットが再構築されます。AliExpress基本クラスを使用することの欠点は、状態が最終的なものであり、状態を変更する場合に問題が発生することです。

スコープモデル:これは、放棄されたウィジェットの上に構築された外部パッケージであり、状態にアクセス、更新、および変更するための少し優れた方法を提供します。これにより、データモデルを親ウィジェットからその子孫に簡単に渡すことができます。さらに、モデルが更新されたときに、モデルを使用するすべての子を再構築します。

これにより、モデルのScopedModelDescendantsの数によっては、更新があると再構築されるため、パフォーマンスの問題が発生する可能性があります。

この問題は、ScopedModelを複数のモデルに分解して、よりきめ細かい依存関係を取得することで修正できます。rebuildOnChangeフラグを設定falseするとこの問題も修正されますが、再構築するウィジェットを決定するという認知的負荷が伴います。

Redux:はい!Reactと同様に、FlutterでReduxストアを簡単に作成して利用するのに役立つReduxパッケージがあります。JavaScriptに対応するものと同様に、通常は数行の定型コードと、アクションレデューサーのラウンドトリップがあります。

BLoCパターンを入力してください

ビジネスロジックコンポーネント(BLoC)パターンは、Googleによって作成され、Google I / O'18で発表されたパターンです。BLoCパターンは、リアクティブプログラミングを使用して、アプリ内のデータフローを処理します。

BLoCは、アプリ内のデータのソース(API応答など)とデータを必要とするウィジェットの間の仲介役として機能します。ソースからイベント/データのストリームを受信し、必要なビジネスロジックを処理し、データ変更のストリームをそれらに関心のあるウィジェットに公開します。

BLoCには、シンクストリームの2つの単純なコンポーネントがあり、どちらもStreamControllerによって提供されます。あなたはにイベント/データ入力のストリームを追加シンクとを介してデータ出力のストリームとしてそれらに耳を傾けるストリーム

A StreamControllerを介してアクセスすることができる‘dart:async’ライブラリ又はPublishSubjectReplaySubject又はBehaviourSubjectを介してrxdartパッケージ。

以下は、単純な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 ); } ...

BLoCは単純なDartクラスです。上記のコードスニペットでは、CounterBlocクラスを作成し、そのStreamController中にを呼び出しましたcounterController。と呼ばれるストリームのゲッター、呼び出されたときにシンクにデータを追加getCountするupdateCountメソッド、およびdisposeStreamControllerを閉じるメソッドを作成しました。

ストリーム内のデータにアクセスするために、StreamBuilderウィジェットを作成し、ストリームをそのstreamプロパティに渡し、そのbuilder関数内のデータにアクセスしました。

BLoCの実装

デフォルトのFlutterサンプルアプリをBLoCを使用するように変換します。先に進んで、新しいFlutterアプリを生成しましょう。ターミナルで次のコマンドを実行します。

$ flutter create bloc_counter && cd bloc_counter

お気に入りのエディタでアプリを開きとlibフォルダ内の3つのファイルを作成しますcounter.dartcounter_provider.dartcounter_bloc.dart

私たちはCounterProvider、整数と、それをインクリメントする方法が含まれます。次のコードをcounter_provider.dartファイルに追加します。

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

次に、カウンターBLoCを実装します。以下のコードをcounter_block.dartファイルに追加します。

このCounterBlocクラスでは、上記の最初のサンプルコードの一部を使用しました。7行目でCounterProviderクラスをインスタンス化し、updateCountメソッドでプロバイダーメソッドを呼び出してカウントをインクリメントし、13行目でカウントをSinkに渡しました。

main.dartファイル内のコードを以下のコードに置き換えます。以下のコードでは、デフォルトのカウンターコードのほとんどを削除しただけで、counter.dartファイルに移動します。incrementCounterメソッドが呼び出されるたびに、updateCountカウントを更新してシンクに追加するBLoCのメソッドを呼び出します。

現在、BLoCはデータを受信して​​ストリーミングしています。そのデータにアクセスし、StreamBuilderを介して画面に表示できます。データを必要とするウィジェットをStreamBuilderウィジェットでラップし、データを含むストリームをそれに渡します。次のコードをcounter.dartファイルに追加します。

上記のコードには、ステートフルウィジェットがあります。状態クラスの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.

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.

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.