Flutter連携はコンテナ所有を明確にする。

ProviderScope は内部生成コンテナを自動破棄し、外部注入コンテナは呼び出し側で破棄します。Consumer系APIは Riverpod 互換の書き味を保ちます。

ProviderScope の所有モデル

コンテナを誰が作るかで dispose 責務が変わります。

内部コンテナ

ProviderScope(child: ...) は自動 dispose

外部コンテナ

ProviderScope(container: c, ...) は c.dispose() が必要

Uncontrolled

UncontrolledProviderScope は dispose しない

注意

Widgetテストで外部注入コンテナを使う場合、未破棄のまま終了するとタイマー由来のリーク原因になります。

Consumer の使い分け

すべて WidgetRef を扱えます。UI構造に合わせて選びます。

アプリ起点

runApp(const ProviderScope(child: MyApp()));

用途

Consumer: 小さな領域だけリアクティブにしたい場合。
ConsumerWidget: build(context, ref) で完結する場合。
ConsumerStatefulWidget: ローカル状態と ref の両方が必要な場合。

例: ConsumerStatefulWidget

ローカルUI状態と Provider状態を同時に扱う典型例です。

home_page.dart
class HomePage extends ConsumerStatefulWidget {
  const HomePage({super.key});

  @override
  ConsumerState<HomePage> createState() => _HomePageState();
}

class _HomePageState extends ConsumerState<HomePage> {
  bool expanded = false;

  @override
  Widget build(BuildContext context) {
    final user = ref.watch(currentUser);
    return Column(
      children: [
        Text('$user'),
        Switch(
          value: expanded,
          onChanged: (v) => setState(() => expanded = v),
        ),
      ],
    );
  }
}
Consumer 実装は更新通知をポストフレームへ送るため、build中の setState 競合を減らします。
再描画が必要な値だけ ref.watch し、副作用は build 外に分離します。
更新処理はコールバック内で ref.invoke / ref.refreshValue を実行します。

次のステップ

テスト

コンテナの所有モデルと override をユニット/Widgetテストで検証します。

テストを開く

APIリファレンス

ProviderScope、WidgetRef、ProviderContainer の主要シグネチャを確認します。

APIリファレンスを開く