search
LoginSignup
1

More than 1 year has passed since last update.

posted at

updated at

flutter_blocを使ってみる その3

flutter_blocのExampleの説明の続きです。「+」「-」ボタンを押した際に使われるBLoCのコードを解説します。

BLoCの説明

「+」「-」ボタンを押すと中央の数値が増減しますが、これはCounterBlocを使っています。

動作の説明

  • ユーザーがボタンを押す等の作業により、UIがBLoCにEventを送る
  • 呼び出されたBLoCのメソッドがStateを変更して、その変更を通知する。
  • 新しいStateを通知として受け取ったUIが再描画する。

Cubitと異なるのはUIがメソッドを呼び出すのではなく、Eventを送ることです。通常Eventは複数種類あり、その中のひとつを送ります。
今回のExampleでは「+」ボタンを押すと CounterEvent.increment、「-」を押すとCounterEvent.decrementを送ります。このExampleではCounterEventenumになっています。

BLoCの中身の動作の説明

  • int型初期値0のStateを持ちます。
  • UIから受け取ったイベントに応じてmapEventToState()メソッドがStateを変更して通知します。

コードの説明

BLoCのコードはこのようになっています。

// Eventをenumで定義、incrementとdecrementの2つを持つ。
enum CounterEvent {
  increment,
  decrement
}

class CounterBloc extends Bloc<CounterEvent, int> {
  // 初期値を0に設定する
  CounterBloc() : super(0);

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    // Eventの種類によってStateを変更して通知する
    switch (event) {
      case CounterEvent.decrement:
        yield state - 1;
        break;
      case CounterEvent.increment:
        yield state + 1;
        break;
      default:
        addError(Exception('unsupported event'));
    }
  }
}

UIのコードの抜粋です。

class CounterPage extends StatelessWidget {
// ...省略
// Stateを受け取って再描画する。
body: BlocBuilder<CounterBloc, int>(
  builder: (_, count) {
    return Center(
      child: Text('$count', style: Theme.of(context).textTheme.headline1),
    );
  },
),
// ...省略
// FloatingActionButtonを押すとCounterEvent.increment(or decrement)が送られる
FloatingActionButton(
  child: const Icon(Icons.add),
  onPressed: () => context.read<CounterBloc>().add(CounterEvent.increment),
),
//...省略

もう少し詳しい説明

flutter_blocにてBLoCはEventのStreamを受け取り、StateのStreamを通知(broadcast)します。コードをみると mapEventToState() メソッドがStreamを受け取りStreamを返していることがわかると思います。
これは例えばデータ取得の際に、まずLoadingState、次に取得結果に応じてSuccessStateまたはErrorStateを通知するというように、複数のStateを順次通知するような挙動を前提としています。

コードで書くと以下のようになります。Loading中はViewにスピナーを表示しておいて、データが取得できたらリストを表示する、というようなことができますね。

if (event is FetchData) {
  yield LoadingState();
  try {
    final data = await repository.getData();
    yield SuccessState(data);
  } catch (error) {
    yield ErrorState(error);
  }
}

BLoCとCubitとの違い

これまでにBLoCとCubitの挙動を説明したので、両者の違いも説明できるかなと思います。

  • BLoCは複数種別のEventを受け取ることができるが、Cubitは複数種別を扱えない
    • ExampleではCubitはColorThemeの切り替えのみ、BLoCは数値のインクリメント、デクリメントの2種類のイベントを使っている
  • BLoCは連続したEventをStreamで受け取り都度StateをStreamで返すが、CubitはひとつのEventを処理する
    • BLoCのmapEventToState()はStream型のメソッドだが、Cubitのemit()はvoidとなっている

こんな感じで使い分けるといいと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1