モチベーション
- 長らくFlutterにおける標準WidgetのFormとお付き合いをしていたところ、どうみても巷に蔓延っているFormに関わるサンプルコードは「想定していない使い方」だと確信したので、ここに記す。
- いうて公式のサンプルコードもだいぶひどい。各フォーム値の取得方法に関して何も書いてないし...
コードの全容
See the Pen Flutter Form Demo by hummer (@hummer98) on CodePen.
ポイントその1: 意味もなくsave()するな
- 前の記事にも書いたが、
_formKey.currentState.save()
は、Formの子孫にあるFormFieldのonSave()
を呼び出しているだけ。 - onSaveを書いてないなら何の意味もない行為である。
-
_formKey.currentState.validate()
のあとのおまじないやめよ?
ポイントその2: 意味もなくステートを持つな
- フォームで使う値を一生懸命
var String email
とかやって保持している書き方が多いが、FormFieldState
にGlobalKey
張れば、フォームの現在値にはアクセスできる。 - フォーム値の出し入れ等が特殊であるようなカスタムFormFieldを使っているのでも無いかぎり、わざわざ
StatefulWidget
にして値を保持しsetState()
をして現在のフォームに入力されている値を保持しようとするのは意味がない。- フィールドが10個とかだと, さすがに
GlobalKey
を作りまくって出し入れするのがダルいので、素直にreactive_formsを使ったほうが早い。とても良いフォームライブラリです。(AutofillHints対応あくして→自分でPRしてどうぞ?)
- フィールドが10個とかだと, さすがに
ポイントその3: やたらめったらFormを書き換えるな
-
FormField
系はわりと重いWidgetなので、バカスカ書き換えるのはやめたほうがいい。 - そもそも
StatefulWidget
なので、入力値が変われば勝手に書き換わるし、バリデーションがコケれば発生すれば勝手にrebuildしてエラーメッセージを表示する- 上記コードを動かしてみればLoginFormのrebuildが最初の1回だけで、あとはエラーが出ようが入力されようが一切rebuildされてないのがわかるはず
- 外からバカスカsetStateして書き換える必要は皆無(大事なことなので2度
ポイントその4: 初期値を入れるのにTextEditingControllerを使うな
- 初期値を入れるには
TextEditingController
を使えとか書いてあるblogがあるが、意味不明である。 - その名もずばり
TextFormField.initialValue
があるのでそれを使えば良い。
ポイントその5: AutofillHintsちゃんと書こう
- 各OSにテキストフィールドの入力支援をさせるために、
TextFormField.autofillHints
(HTML.Inputタグで言うところのautocomplete属性)をセットしておこう - これをやっておくだけでユーザー体験が劇的に向上する
元凶と経緯
- FormWidgetは元来
_fields
というchild以下の各フォームのアクセサを持っているのにもかかわらず、この配列がprivate
になっていて、ユーザから触れない - そのため、FormFieldそれぞれに
GlobalKey<FormFieldState>
を張っていかないと、フォームの現在値にアクセスすることができない。 - Formに関する公式のドキュメントを眺めていても、肝心のフォームの現在値にアクセスする手段がわからない(公式にもちゃんと書いてない)ので、思い思いの実装によって解決するBlogが蔓延してしまったのではないだろうか。
- →なにもかも公式が悪い
おまけ
外からフォームの値を書き換えたいとき
-
FormFieldState<T>.didChange(T value)
(公式doc)を使う。-
_fieldKey.currentState.didChange(newValue);
みたいな感じ
-
- ちなみに
setValue
(公式doc)はprotected
なので、カスタムしたいFormFieldを継承して作成するときに使う模様。
EnterキーでSubmitしたいとき
- WebFormだとよくある動作
- ちゃんとやるとキーボードイベントを取得して判定するべきなんだけど、雑にやるなら
onFieldSubmitted
にボタンのsubmitと同じ処理を呼び出すようにしておくと、同じような感じに動く。
まとめ
- 標準のFormはめっちゃ使いにくいのでReactiveForm使いましょう!
Follow Me!
- Twitter: hummer