はじめに
Flutter界隈盛り上がってますね。公式ドキュメントも充実して、Chromeの翻訳機能を使えば、感覚を掴んでどんどん開発できていくと思います。アーキテクチャについて詳解はあってもカジュアルな記事が少ないなあと思ったので、私見ではありますが、まとめたいと思います
結論: Providerを使おう
2019年のGoogle I/Oで発表された、Provider(https://pub.dev/packages/provider) を使って開発するのがお手軽で良いと思います。ProviderはInheritedWidgetをラップして、データのBuildContextへの埋め込み、BuildContextからのデータの取り出しをカンタンに行えるようにするライブラリーです
Flutter開発あるある
iOS開発では、StoryBoardで画面を作成し、UIViewControllerとStoryBoardをIBOutletで紐付けることで、UIViewController上のSwiftコードから、データの表示などUIを操作することができました。
Flutterでは、Widgetと呼ばれるUI部品で組合せて画面を作成します。このWidgetは階層構造になるため、階層の深いWidgetに対してデータをどのように受け渡していくかが問題になります。
Providerを使わない場合、コンストラクターでひたすら引き回すようなコードを良く見かけます
Providerを使うと
Provider.value
を使ってBuildContextに埋め込んだデータを、下位のWidgetでProvider.of<String>(context)
を使って、簡単に取り出すことができます。
データの注入の方法にはProviderの種類に応じて複数種類ありますので解説していきます。
ChangeNotifierProvider
例えばフォームのように画面からの入力を受け付け、リアルタイムに変更を保持したい場合は、ChangeNotifierProvider
を使うとお手軽です。下記のようなViewModel
クラスを作成します。
モデルクラス
class HogeHogeViewModel with ChageNotifier {
String name;
setName(String name) {
this.name = name
notifyListeners();
}
}
ポイントは、ChageNotifier
をmixinすること、セッターでnotifyListeners()
を呼び出すことです。
注入するコード
ChangeNotifierProvider<HogeHogeViewModel>(
create: (_) => HogeHogeViewModel(),
child: HogeWidget()
)
HogeWidget
はデータを注入する対象のWidgetです。
利用する側
Provider.of<HogeHogeViewModel>(context)
注入したWidgetより下位のWidgetではBuildContextから簡単にHogeHogeViewModel
を取り出すことができます。
また、このViewModelを画面単位に用意し、画面を返すWidgetに下記のメソッドを用意、呼び出し元で呼び出すことで、自動的にモデルクラスが画面全体に注入され、画面に関する全てのデータ・ロジックをモデルクラスに集約できます。
画面のWidget
class HogeScreen extends StatelessWidget {
static Widget withDependencies() => ChangeNotifierProvider<HogeHogeViewModel>(
create: (_) => HogeHogeViewModel(),
child: HogeScreen()
);
}
InheritedWidgetとの関係
Flutterには、InheritedWidget
という、上位のWidgetに対して、ツリーをたどるのではなくハッシュマップを使って、計算量O1でアクセスでき、InheritedWidget
の下位のWidgetのみbuildを行う仕組みがあります。ProviderはInheritedWidget
を便利に使えるようにされたラッパーでです。
まとめ
Flutterは、まだまだ発展途中ですが2019年12月の時点では、Provider
とViewModel
を使うとサクッとコードを実装できて良さそうです。次は、FirestoreとStreamについてまとめてみます。
追記
アーキテクチャ2を書きました
https://qiita.com/sarukun99/items/4057ae3c0801a3bfcfd7