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 の挙動は変わりません。