リアクティブプログラミング(Rx)入門:状態管理からフラグ排除まで
1. はじめに
Flutterの状態管理にはいくつかの選択肢がある。日本で最もポピュラーなのはRiverpodだろう。状態管理のしやすさに関してリアクティブプログラミング(Reactive Programming, 以下Rx)を採用するのはハイスキルのプログラマーを抱えるチームにおいて有効な選択肢と言える。本稿はまだRxを知らないFlutter開発者向けに記載された。ハイスキルではないプログラマーでも十分に理解できるように書いている。
Rxは、状態の変化をリアルタイムに検出し、それに応じてUIや処理を自動的に反映させる設計思想だ。FlutterではGetX、AndroidではJetpack ComposeとKotlin Flow、iOSではSwiftUIとCombineの組み合わせがRxの思想に基づいている。
特にFlutterなどのモダンなUIフレームワークでは、フラグの乱立による状態管理の煩雑さを解消するためにRxの考え方が役立つ。
2. 状態管理とフラグ地獄の問題点
従来のImperative(命令的)プログラミングでは、処理の進行状態を管理するために次のようなフラグを多用する:
bool isLoading = false;
bool hasError = false;
bool isSuccess = false;
このような設計は以下の問題を生む:
- 相互排他性を保証しにくい(同時に複数の状態がtrueになりうる)
- UIと状態が乖離しやすい
-
スパゲッティコード化しやすい
3. Rxの基本概念
Rxでは、状態はすべて**ストリーム(流れ)**で表現されます。
final count = RxInt(0);
この count
は 0
という値を持つストリーム(Observable)であり、変更されるたびにそれを監視しているUIや処理に通知され。
4. 状態を1つの列挙体に集約する
状態を enum
にまとめて扱うことで、フラグを排除し、状態の排他性を自然に担保できる:
enum LoadState { initial, loading, success, error }
final loadState = Rx\<LoadState>(LoadState.initial);
利点:
- 状態が1つしか選べない(排他性の担保)
-
UIの
when
表現が容易になる -
状態が明確で変更が追いやすい
5. 状態に応じたUIの切り替え
Obx(() {
switch (controller.loadState.value) {
case LoadState.initial:
return Text("初期状態");
case LoadState.loading:
return CircularProgressIndicator();
case LoadState.success:
return Text("完了!");
case LoadState.error:
return Text("エラー発生");
}
})
これにより、複数の isXxx
フラグによる if
/ else
よりも遥かに読みやすく、保守しやすくなる。
6. 非同期処理との統合
Future\<void> fetchData() async {
loadState.value = LoadState.loading;
try {
await repository.getSomething();
loadState.value = LoadState.success;
} catch (\_) {
loadState.value = LoadState.error;
}
}
Rx
と非同期処理の統合で得られる効果
- 状態遷移の流れが一目瞭然
-
UIとの自動同期
-
エラー処理の一元化
7. まとめ
課題 | 従来のImperative方式 | Rx方式(推奨) |
---|---|---|
状態表現 | 複数のフラグ | Enum + Rx |
UI更新 | 手動でsetState()等 | 自動反映(Obx, watch) |
保守性 | スパゲッティ化 | 明確な状態遷移 |
8. 補足:Riverpodでの対応
Riverpodでは AsyncValue
や StateNotifier<State>
などで同様のアプローチが取れる:
final loadStateProvider = StateProvider\<LoadState>((ref) => LoadState.initial);
また、非同期処理の状態は AsyncValue<T>
で一元管理:
final userProvider = FutureProvider((ref) async {
return await repository.fetchUser();
});
9. 参考
- GetX: https://pub.dev/packages/get
-
Riverpod: https://riverpod.dev
-
Rxの本家: https://reactivex.io/
最後に
Rxを用いた状態管理は、モダンなアプリ開発において極めて重要なスキルだ。特に状態遷移とUI更新の自動化により、フラグ管理に悩まされない安定したコードが書けるようになる。