UIで使うデータクラスのメンバー変数にIterableでデータを持たせていた。Listが持つaddやらなんやらをしてほしくないからそもそもそういうIFを提供しないのが良いと思っていた。
@freezed class User with _$User { User({ required Iterable<Favorite> favorites, }) = _User; }
一方で、DartのIterableは遅延処理される。
例えば以下のようにmapの中で例外を投げる実装があったとする。これは遅延処理されるので、buildメソッド内で例外が発生しうる。
@freezed class User with _$User { User({ required Iterable<Favorite> favorites, }) = _User; } final provider = FutureProvider((ref) async { final user = await ...; // なんらかの方法でUserResponse取得 return User(favorites: user.favorites.map((e) { swtich (e) { case ...: return Favorite(); case ...: throw UnknownException(); // 例外を投げている } })); }); class UserView extends ConsumerWidget { @override Widget build(context, ref) { final data = ref.watch(provider); // AsyncValue<User>を返す。ここではまだmapの内容は評価されていない return data.map(data: (data) { print(user); // ここではまだfavoritesは評価されていない return FavoritesView(data.favorites); // ここでfavoritesが評価されるので、ここで例外が投げられる可能性がある }, loading: (_) {}, error: (_) {}); } }
どこで評価されるのか/すでに評価済みかもわからないので、AsyncErrorにいくと思って書いていても、buildメソッド内で例外が起きてしまう。そしてbuildメソッド内で例外が起きるとErrorWidget.builderを定義していない限りWidgetが表示されないのでユーザーはなにが起きてるのかわからない。
Hixieさんは、buildメソッド内で例外を投げないことを推奨すると言ってる。それを防ぐ仕組みがないのにそんな無茶な…と凡人の自分は思うのだが、まあ言ってるのでしょうがない。
Widgetで利用するデータは、すべて評価済みのものを渡すのがよさそう。そう考えるとUIで使うデータクラスは、基本的にListに依存するのがよく、必要であればIterableとするのがよいのかもしれない。