ゆめみ Flutter 研修で学んだことのメモ (課題クリアに必要な知識以外)
研修リポジトリ: GitHub - daichikuwa0618/flutter-weather-app: Dummy Weather App Built with Flutter にて学んだことのメモ。
ただし、課題をクリアするのに必要な知識は除く。 (例えば Session/4 で求められている Mixin とは何かみたいな話は含んでいない)
[Session/1] 天気予報画面の UI 作成 #14
XxxPage
と XxxScreen
の命名について
https://github.com/daichikuwa0618/flutter-weather-app/pull/14#discussion_r1602679988
画面 Widget の接尾辞の流派は主に Page と Screen があります。Screen だと WeatherScreen ですね。
なぜ Screen を好む流派がいるかというと、Flutter には Page クラスが存在して、それは Widget ではなくルーティングに関係するクラスなので、WeatherPage だとルーティングに関係するように撮られる可能性があるからです。
[Session/2] "Reload" タップで天気予報情報を同期的に取得し画面に表示 #15
Callable Object について
https://github.com/daichikuwa0618/flutter-weather-app/pull/15#discussion_r1602534343
Swift でいうところの callAsFunction を Dart でも利用する にまとめた。
[Session/3] StatefulWidget のライフサイクル #16
Future.unawaited
と Future.microtask
って何が違う?
https://github.com/daichikuwa0618/flutter-weather-app/pull/16#discussion_r1604448233
The Event Loop and Dart (翻訳) #Dart - Qiita を見るのが一番良かった。
Future.microtask & addPostFrameCallback その違い も良かった気がするけど、忘れちゃった。時間があったら見よう。
[Session/6] JSON を扱って気温情報を表示 #19
Extension Type の利用
https://github.com/daichikuwa0618/flutter-weather-app/pull/19#discussion_r1609187243
extension type _Request(({String area, DateTime dateTime}) value) {
Map<String, String> toJson() {
return {
'area': value.area,
'date': value.dateTime.toString(),
};
}
}
一見 record 型を typedef
すればいいんじゃ?と思うかも知れないが、メソッドや getter を生やすときに違いが出てくる。
↓ は雰囲気で書いたから違うところあるかも。
// typedef 板
typedef MyInt = int;
Extension on MyInt {
MyInt double() {
return this * 2;
}
}
MyInt myInt = 1;
myInt.double();
int pureInt = 1;
pureInt.double(); // できちゃう
extension type MyInt(int value) {
MyInt double() {
return this * 2;
}
}
var myInt = MyInt(1);
myInt.double();
int pureInt = 1;
// pureInt.double(); // MyInt として静的に型付けされてないとできない
生成コストの無い独自型って感じで、自前の型を作りすぎないでプリミティブな型で表現する データ指向プログラミング と相性が良さそう (多分)。
[Session/7] freezed による JSON シリアライズの導入 #20
toJson メソッドのみを生成させる方法
https://github.com/daichikuwa0618/flutter-weather-app/pull/20#discussion_r1611052469 このコメント時点では良く分かってなかった。
後で分かったのでまとめた: freezed で toJson だけ生成させる方法
[Session/8] riverpod を使った状態管理に変更 #21
ローカル状態は Riverpod で提供しない
- ephemeral state については hooks / StatefulWidget を利用
- app state については Provider を利用
AVOID using providers for local widget state.
Providers are designed to be for shared business state. They are not meant to be used for local widget state, such as for:
- storing form state
- currently selected item
- animations
- generally everything that Flutter deals with a "controller" (e.g.
TextEditingController
)If you are looking for a way to handle local widget state, consider using flutter_hooks instead.
One reason why this is discouraged is that such state is often scoped to a route.
Failing to do so could break your app's back button, due to a new page overriding the state of a previous page.
Provider の設計は難しいということ
テストのことを考えると family Provider を作るよりも Function を返す Provider の方が書き味がいい みたいな話もあるが、その場合は他の画面から呼び出したときに値がキャッシュされない (ですよね?)
XxxRepository
みたいに何かしらのオブジェクトを返す Provider を作っても ref.xxxProvider.getXxx()
を他の場所から呼ぶとキャッシュされた値が使われるのではなく、改めてメソッドが実行される (ですよね?)
となると、キャッシュ戦略に寄っては Family Provider も使い所次第で積極的に使っていけば、同じ引数のものは不要な API 通信や DB 操作が無くせるというのは結構大きなメリットに感じる。
特に、SSOT を守りやすくなりそう。 (更新をかけたいタイミングで invalidate すれば全部の画面でリフレッシュされるので)
- 同じ引数であればキャッシュが利用可能
- Family Provider
- キャッシュが効かず、再度メソッドが実行される
- Repository 等のオブジェクトを返す Provider (DI コンテナ的に使う考え方)
Result Function(Arg)
を返すような Provider- テストのことを考えると family Provider を作るよりも Function を返す Provider の方が書き味がいい みたいな動機で Family Provider を避けた場合
[Session/9] Uni Test の追加 #22
ここはテストコード丸々が結構面白いんじゃないかと思っている。
flutter-weather-app/test/weather/weather_notifier_test.dart
やりたいこととしては、Notifier が依存している Use Case の結果が変わったときに、期待する状態になっていること。単独の結果ではなく、失敗 → 成功等の前回の結果に依存するテストを書きたい。