Reactive Programmingとは普通の(Imparative)Programmingとどう違う

投稿者: | 2025年6月5日

リアクティブプログラミング(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);

この count0 という値を持つストリーム(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では AsyncValueStateNotifier<State> などで同様のアプローチが取れる:

final loadStateProvider = StateProvider\<LoadState>((ref) => LoadState.initial);

また、非同期処理の状態は AsyncValue<T> で一元管理:

final userProvider = FutureProvider((ref) async {

return await repository.fetchUser();

});


9. 参考


最後に

Rxを用いた状態管理は、モダンなアプリ開発において極めて重要なスキルだ。特に状態遷移とUI更新の自動化により、フラグ管理に悩まされない安定したコードが書けるようになる。

コメントを残す