miniriverpod の設計原則。

機能を絞る代わりに挙動を明確化しています。args による同一性、Scope による注入、予測しやすい破棄ルールが中心です。

Riverpod との違い

family 専用型や暗黙 notifier 経路の代わりに、subclass + args + invoke を採用しています。

Provider同一性

runtimeType + args のハッシュ

family相当

Provider / AsyncProvider を継承し super.args((...)) を使う

DIのフォールバック

Scope<T>.required + overrideWithValue

重要ポイント

通常の Dart コンストラクタだけで同一性と override を追えるため、デバッグとテストが単純になります。

args による Provider 同一性

args が ProviderKey を決めるため、同じ args は同じキャッシュエントリとして扱われます。

同一性ルール

ProviderKey = runtimeType + hash(args)

実務への影響

- family 専用の型は不要です。
- 引数ごとの override は Provider インスタンス単位で行います。
- 予測可能なキャッシュのため、args は不変オブジェクトで管理します。

例: family相当 + Scopeフォールバック

コンストラクタ引数を同一性に使い、Scope 経由でフォールバックインスタンスを注入します。

product_provider.dart
class ProductProvider extends AsyncProvider<List<Product>> {
  ProductProvider({this.search = ''}) : super.args((search,));
  final String search;

  static final fallback = Scope<ProductProvider>.required('product.fallback');

  @override
  FutureOr<List<Product>> build(ref) async {
    final api = ref.watch(productsApiProvider);
    return api.search(q: search);
  }
}

// 注入
ProviderScope(
  overrides: [
    ProductProvider.fallback.overrideWithValue(ProductProvider(search: 'jeans')),
  ],
  child: const App(),
);
Scope を使うと依存注入の意図が明確になり、テストしやすくなります。
overrideWithValue は args 付き Provider インスタンスにもそのまま使えます。
subclass + args でも autoDispose の挙動は変わりません。

次のステップ

Providerと読み取り

watch/read/listen と AsyncProvider.future の実践パターンを確認します。

Providersを開く

ミューテーション

mutation token、mutate、ref.invoke で更新処理を実装します。

Mutationsを開く