Riverpod — Flutterのためのコンパイル済み依存関係管理

著者: IT Sectr 公開日: 2026-02-19 読了時間: 7 分

Riverpod — Flutterのためのコンパイル済み状態および依存関係マネージャーで、2021年にRemi RousseletがProviderの後継として作成しました。RiverpodはProviderの根本的な問題を解決します:コンパイル時チェックの欠如、BuildContextへの依存、ProviderNotFoundExceptionの複雑さ。pub.devによると、このパッケージは5000以上のいいねを獲得し、新しいプロジェクトでProviderを積極的に置き換えています。

重要なポイント

  • ProviderRef — プロバイダー内で他のプロバイダーにアクセスするためのオブジェクト
  • AsyncValue — loading/error/data状態を持つ非同期データのラッパー
  • Notifier — 変更メソッドを持つミュータブル状態のクラス
  • ProviderScope — すべてのプロバイダーを管理するルートウィジェット
  • Code Generation — 自動プロバイダー生成のための@riverpodアノテーション

Riverpodとは?

Riverpodは、プロバイダーの記述を安全なDartコードにコンパイルする、Flutter向けの状態管理および依存関係注入ライブラリです。Providerとは異なり、RiverpodのプロバイダーはBuildContextに縛られません:グローバルまたはProviderScope内で作成され、どこからでもアクセス可能です。コンパイラはビルド時に型、依存関係、プロバイダーグラフの整合性をチェックし、ProviderNotFoundExceptionのような実行時エラーを排除します。

Riverpodはテストにoverrideモデルを使用します:各プロバイダーは、サブクラスを作成したりインターフェースをモックしたりせずに、ProviderScope.overrideWithを介してオーバーライドできます。これによりテストが分離されます:各テストは完全に制御された依存関係グラフの独自のコピーを取得します。

Flutter Community Survey 2025によると、RiverpodはProviderとBLoCに次いで人気で第3位です。しかし、Riverpodは最も急速に成長しているパッケージです:2024年に+120%のインストール増。主な理由:コンパイル時の安全性、ProviderNotFoundExceptionの不在、AsyncValueによる組み込み非同期サポート。

プロバイダーの種類

Riverpodは8種類のプロバイダーを提供し、それぞれ特定のシナリオに対応します:Provider(定数/サービス)、StateProvider(プリミティブ状態)、StateNotifierProvider(StateNotifierを使用した複雑なロジック)、ChangeNotifierProvider(Providerからの移行用)、FutureProvider(非同期データ、1回限り)、StreamProvider(リアクティブストリーム)、NotifierProvider(新しいAPI、Flutter 3.10+)、AsyncNotifierProvider(非同期Notifier)。

Dart
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);

  void increment() => state++;
  void decrement() => state--;
}

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  }
}

ProviderRef — 他のプロバイダーにアクセスするために各プロバイダーに渡されるオブジェクト。ref.watch — 変更の購読、ref.read — 1回限りの読み取り、ref.invalidate — キャッシュのリセット。ProviderRefはProviderのBuildContextを置き換えます:任意のプロバイダーがウィジェットツリーにアクセスせずに他のプロバイダーを読み取れます。これによりUIレイヤーの外部で依存関係グラフを構築できます。

ProviderScope — Riverpodが機能するために必須のルートウィジェット。ProviderScopeはすべてのプロバイダーを保存し、それらのライフサイクルを管理し、値をキャッシュします。ProviderScopeがないと、アプリはProviderNotFoundExceptionでクラッシュします。ProviderScopeはネスト可能で、ネストされたスコープは親プロバイダーをオーバーライドし、テストや機能の分離に使用されます。

AsyncValueと非同期処理

AsyncValue — 非同期状態を表現するためのRiverpodのシールドクラス。AsyncValueには3つのバリアントがあります:AsyncData(成功データ)、AsyncError(エラー)、AsyncLoading(ローディング)。loading/error/dataを手動で切り替える代わりに、各FutureProviderまたはStreamProviderが自動的にAsyncValueを返し、ウィジェットがref.watchを介して3つの状態すべてを処理します。

Dart
final userProvider = FutureProvider((ref) async {
  final api = ref.watch(apiProvider);
  return await api.fetchUser();
});

class UserScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userAsync = ref.watch(userProvider);
    return userAsync.when(
      data: (user) => UserWidget(user),
      error: (e, _) => ErrorWidget(e.toString()),
      loading: () => CircularProgressIndicator(),
    );
  }
}

AsyncValue.when — 3つの状態すべてをパターンマッチングするメソッド。コンパイラは3つのケースすべてが処理されていることを確認します — loadingまたはerrorを忘れると、コードはコンパイルされません。AsyncValue.whenData — データのみ(loading/errorが必要ない場合)。AsyncValue.guard — 例外をAsyncErrorに変換するためのtry-catchのラッパー。keepAlive — プロバイダーキャッシュがスコープ外に出たときに破棄されるのを防ぐフラグ。

コード生成と@riverpod

コード生成 — Riverpod 2.0+の主要機能。関数に@riverpodアノテーションを付けると、正しい型、リファクタリングサポート、オートコンプリートを備えたプロバイダーが自動生成されます。コード生成はriverpod_generatorbuild_runnerを使用します。開発者が純粋関数を書くと、型、クラス、ファクトリコンストラクタなど、残りのすべてが自動生成されます。

Dart
@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello World';
}

// 生成: final helloWorldProvider = Provider((ref) => 'Hello World');

@riverpod
class Counter extends _$Counter {
  int build() => 0;
  void increment() => state++;
}

Notifier — コード生成を伴うミュータブル状態の新しいAPI。Notifierはbuild()メソッドと状態変更メソッドを持つクラスです。StateNotifierとは異なり、Notifierは別の状態クラスを必要とせず、getter/setterを介してstateに直接アクセスできます。Riverpodは@riverpodでアノテーションされた各Notifierクラスに対してNotifierProviderを自動生成します。

build_runner: コード生成はdart run build_runner buildコマンドで実行されます。生成されたファイルには.g.dartサフィックスが付き、ソースコードにインポートされます。アノテーションやプロバイダーの型が変更された場合、コード生成を再実行する必要があります。Riverpod 2.xはすべての新規プロジェクトにコード生成を推奨しています — 手動のプロバイダー作成は非推奨になりつつあります。

Riverpod vs Provider

主な違い RiverpodとProviderの間:BuildContextからの独立性、コンパイル時の安全性、組み込みの非同期サポート、自動キャッシング、overrideによるテスト。Providerは状態にアクセスするためにBuildContextを必要とします(context.watch、context.read)、RiverpodはWidgetRefとグローバルに宣言されたプロバイダーを使用します。

特性ProviderRiverpod
BuildContext依存ありなし
コンパイル時チェックなしあり(@riverpod経由)
ProviderNotFoundException実行時不可能
非同期手動AsyncValue(組み込み)
テストProviderのラッパーProviderScope.overrideWith
キャッシングなし自動 + keepAlive

Providerからの移行: Riverpodは、書き換えなしで既存のChangeNotifierを使用するためのChangeNotifierProvider.adaptiveをサポートしています。段階的移行:最初に新機能をRiverpodで書き、次に古いProviderインスタンスをアダプターを介してRiverpodプロバイダーに置き換えます。両方のパッケージが1つのプロジェクトで共存できるため、開発を凍結せずに移行できます。

Riverpodのテスト

RiverpodのテストはProviderScope.overrideWithに基づいています。各プロバイダーは、モックやDIコンテナなしでテスト用ProviderScope内でオーバーライドされます。ProviderContainer — Flutterなしのテスト用の分離環境(純粋なDart)、ウィジェットレンダリングなしでプロバイダーをテストできます。

Dart
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/riverpod.dart';

void main() {
  test('Counter increments correctly', () {
    final container = ProviderContainer();
    container.read(counterProvider.notifier).increment();
    expect(container.read(counterProvider), 1);
  });

  testWidgets('UI updates on increment', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [counterProvider.overrideWithValue(5)],
        child: CounterScreen(),
      ),
    );
    expect(find.text('5'), findsOneWidget);
  });
}

ProviderContainer — Flutterなし。ウィジェットなしでプロバイダーのユニットテストにはProviderContainerを使用します。overrideWithValue — 特定の値でプロバイダーを置き換える。overrideWith — プロバイダーファクトリで置き換える(サービスのモック用)。autodispose — テストでは、container.dispose()を使用してプロバイダーがスコープ外に出たときに破棄されることを確認します。

よくある質問

RiverpodとBLoCの違いは何ですか?

Riverpodは、グローバルプロバイダー、AsyncValue、コード生成を備えた状態管理ライブラリです。BLoCは、Event → Stream → Stateのアーキテクチャパターンです。Riverpodは学習が容易で、@riverpodアノテーションによる優れたDXを提供します。BLoCは厳格なビジネスロジックの分離とBlocObserverによるイベントトレーシングを提供します。選択はプロジェクトのパラダイムに依存します:RiverpodはProviderに近く、BLoCはリアクティブストリームに近いです。

Riverpodのautodisposeとは何ですか?

Autodisposeは、誰も購読していないプロバイダーを自動的に破棄するメカニズムです。デフォルトでは、すべてのRiverpodプロバイダーはautodisposeします:ウィジェットがツリーを離れると、プロバイダーはメモリから削除されます。keepAlive — 常に生き続けるべきプロバイダー(APIクライアント、リポジトリ、設定)のautodisposeを無効にするフラグ。これによりメモリリークが防止されます — 未使用のプロバイダーは自動的に破棄されます。

ref.invalidateはどのように機能しますか?

ref.invalidate — プロバイダーキャッシュを強制的にリセットするメソッド。invalidate後、次回の読み取り時にプロバイダーが再作成されます:FutureProviderは非同期関数を再実行し、StreamProviderはストリームに再購読します。データ更新を強制するにはinvalidateを使用します(プルツーリフレッシュ、ユーザー切り替え)。ref.refresh — invalidate + 読み取りの組み合わせ:1回の操作でリセットしてすぐに新しい値を読み取ります。

コード生成なしでRiverpodを使用できますか?

はい。Riverpod 1.xはコード生成なしでのみ動作します — プロバイダーはProvider()、StateNotifierProvider()、FutureProvider()などを使用して手動で作成されます。Riverpod 2.xは両方のアプローチをサポートしています。コード生成なしではボイラープレートが増えますが、build_runnerやdart run build_runner buildへの依存はありません。小規模プロジェクト(30プロバイダーまで)では手動作成が妥当ですが、大規模プロジェクトではコード生成が必須です。

Familyプロバイダーとは何ですか?

Family — 外部パラメータを受け入れるプロバイダーモディファイア。例えば、userProvider(123) — ID 123のユーザーをロードするプロバイダー。Familyプロバイダーは一意のパラメータごとに個別に結果をキャッシュします。各アイテムがIDでロードされるアイテムのリストにはFamilyを使用します。Familyモディファイアはすべてのプロバイダータイプで利用可能です:Provider.family、FutureProvider.family、StreamProvider.family。

まとめ

  • Riverpod — ProviderNotFoundExceptionのない、コンパイル済み状態マネージャー、Providerの後継
  • ProviderRef — 他のプロバイダー内でプロバイダーにアクセスするためのBuildContextの代替
  • AsyncValue — 非同期データのためのloading/error/data状態を持つシールドクラス
  • @riverpodコード生成 — 自動型推論とプロバイダーファクトリ
  • ProviderScope.overrideWith — モックやDIコンテナなしの分離テスト
  • Family — 個別キャッシングを持つパラメータ化されたプロバイダー
  • autodisposeとkeepAlive — 自動プロバイダーライフサイクル管理

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください