🐰

【Flutter】ジェネリクスを活用してfreezedで生成されるファイル数を減らす

2024/02/03に公開

はじめに

Flutterの開発において広く利用されいてる、freezedでは、自分で作成したクラスを作るたびに自動生成のファイルが作成されます。
そのため、クラス数を増やすと自動生成されるファイル数も増え、プロジェクトのファイル数が多くなってしまうデメリットがあります。
そこで、ジェネリクスを使ってクラスを共通化してあげて、自動生成されるファイル数を抑える営みをしてみました。

TODO

今回は、Riverpodパターンにおける、Stateクラスを共通化してみたいと思います。
アーキテクチャについては、以下の記事がとても参考になりました。
https://qiita.com/rhumie/items/f91acf30a640447c57c8#riverpod-pattern

ジェネリクスを使ったコード

例えば、APIを使って何らかのデータ(T)を取得する処理がアプリ内で共通で使われるということであれば、以下のように共通化できそうです。

common_fetch_state.dart
import 'package:freezed_annotation/freezed_annotation.dart';

part 'common_fetch_state.freezed.dart';


abstract class CommonFetchState<T> with _$CommonFetchState<T> {
  const factory CommonFetchState({
    (false) bool isLoading,
    (null) T? result,
    (null) Exception? error,
  }) = _CommonFetchState<T>;
}
  1. API通信中はローディング状態を管理したいため、isLoadingを定義
  2. APIから取得するデータはリクエストするAPIによって異なるのでresultTで定義
  3. 通信エラーなどの例外が発生した場合に備えて、errorを定義

こうしてあげれば、「ユーザー情報」「お知らせ」「投稿一覧」などあらゆるデータの取得処理を1つのStateだけで管理することができます。

今回は、APIによる取得処理を例に挙げましたが、この辺は共通化したいユースケースによってStateの中身を変更できると思います。

使ってみる

使う時はCommonFetchState<HogeModel>のようにしてTとなっているところに任意のModelを入れてあげれば、resultの型が決まるので、取得したい値に応じて処理を書いてあげることができます。

hoge_notifier.dart
// StateProvider
final hogeStateProvider =
    StateNotifierProvider.autoDispose<HogeNotifier, CommonFetchState<HogeModel>>(
  (_) => HogeNotifier(),
);
// Model
class HogeModel {
  HogeModel({required this.hoge});

  final String hoge;
}
// Notifier
class HogeNotifier extends StateNotifier<CommonFetchState<HogeModel>> {
  HogeNotifier({CommonFetchState<HogeModel>? initialState})
      : super(initialState ?? const CommonFetchState<HogeModel>());

  Future<void> fetch() async {
    state = state.copyWith(isLoading: true, result: HogeModel(hoge: ''), error: null);
    Future.delayed(const Duration(seconds: 1));
    state = state.copyWith(isLoading: false, result: HogeModel(hoge: 'hoge'), error: null);
  }
}

Discussion