miniriverpod 背后的设计原则。
这个包刻意收窄功能范围,以保持行为显式:通过 args 定义 provider 标识、Scope 注入,以及可预测的释放语义。
与 Riverpod 的不同之处
相比生成的 family 类和隐式 notifier 通道,miniriverpod 更偏向子类 + args + 显式 invoke。
provider 标识
runtimeType + args hash
family 替代方案
继承 Provider / AsyncProvider,并传入 super.args((...))
DI 回退
Scope<T>.required + overrideWithValue
为什么重要
你可以直接从 Dart 构造函数推理相等性和覆盖规则,这会让调试和测试更简单。
使用 args 定义 Provider 标识
args 定义 provider key,因此相同的 args 在 ProviderContainer 中对应同一个缓存条目。
标识规则
实际影响
- 不需要专门的 family 类型。
- 按参数覆盖通过创建 provider 实例完成。
- 保持 args 稳定且不可变,缓存行为才可预测。
示例:类似 family 的 provider + Scope 回退
把构造函数参数作为标识,并通过 Scope 注入回退实例。
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 对每个 provider 实例都生效,包括基于 args 的实例。
使用子类 + args 不会改变 autoDispose 行为。