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 行为。

下一步

Providers 与读取

查看 watch / read / listen 以及 AsyncProvider.future 的具体模式。

打开 Providers

变更

使用 mutation token、mutate 和 ref.invoke 来实现状态更新。

打开变更