Blocパターンでのフォームバリデーション
最近、Flutterでアプリ開発をしているのですが、Blocパターンでフォームのバリデーションのスマートな実装方法についてまとめられた記事があまりなく、どハマりしました。
そこで今回の記事では、BlocパターンでRxDartを用いたスマートなフォームのバリデーションの実装方法をサインインページを例として紹介したいと思います。
記事の対象:
Rx・flutter初心者
得られる情報
Blocを使ったフォームの実装方法
サインインページの要件は以下の通りとします。
メールアドレス
@を含む1文字以上の文字列
パスワード
8文字以上の英数字からなる文字列
※はてなのシンタックスハイライトが弱いので、今回はあえてスクリーンショットを用いてコードを掲載します。
1. UIを用意する
まずUIを用意します。今回はパスワードとメールの入力欄+送信ボタンのシンプルな構成とします。
2. Blocを用意する
今回は以下のようなBlocクラスを用意します。
ポイントはBehaviorSubjectを使うところです。
BehaviorSubjectはイベントをキャッシュしておいてくれるので、過去のイベントに対し、BehaviorSubject.value
でアクセスできます。
そのため入力情報を保持しておくフィールドを用意しなくてすみます。
Blocでは全ての入出力をStreamにするべきだとありますが、ここではあえてそのルールを破りsubmitをパブリックなメソッドとして定義しています。
なぜならば、ストリームでsubmitを定義すると送信ボタンのonPressedが冗長になってしまうからです。
ストリームで実装すると以下のように冗長な書き方になりますが、
onPressed: () => bloc.submit(null)
メソッドで定義しておくと
onPressed: bloc.submit
と定義でき、UI側のコードがすっきりします。
UIにBlocを注入する
Providerを使ってUIにBlocを注入します。
ついでにTextFieldとRaisedButtonにコールバックを渡します。
Providerはウィジェットの生成と破棄に合わせた処理を渡しておけるので便利です。
ここでProviderの直下にBuilderを配置していますが、これはこのクラス内からProvider.of(context)
でBlocにアクセスするためです。
なぜBuilderを挟む必要があるのかについてはまたいずれ記事にしたいと思います。
バリデーションの実装
いよいよバリデーションを実装していきます。
UI側にバリデーションの結果を伝えるためにStream.addError
とRx.combineStream
を使います
以下はバリデーションを追加したBlocクラスです。
ポイントはRx.combineLatest
を使用することです。
これを使わずに送信ボタンにバリデーションの結果を通知するストリームを用意してもいいのですが、新しくストリームを生成しなければならないうえ、closeもしなくてはなりません。
今回のケースでは気になりませんが、Streamの数が増えるほどStreamの管理がしんどくなってくるので、combineLatestを使った方がスマートだと思います。
UIでバリデーションの結果を受け取る
UIでバリデーションの結果を受け取るにはInputDecoration
クラスのerrorText
を利用します。
StreamBuilderで入力情報のストリームをリッスンしておき、エラーが流れてきたらsnapshot.error
がエラーテキストとして表示されると言った感じです。
また送信ボタンもバリデーションの結果を受け取れるようにしておきます。
コード全体像
コードの全体像は以下の通りです。 UI
おわりに
今回フォームの実装方法を探る中で、Rxdartのコードを読みました。英語が苦手で過ごし面食らいましたが、じっくり読んでみるとかなり丁寧にコメントがされていて、ネットの情報見るよりわかりやすかったので、もし困ったらコードのコメントを読むのをお勧めします。