riverpod 作为状态管理只需要
- stateprovider
- ref.read 获取 stateNotifier 和 state
- ref.listen 监听 state 的变化
作者本人也说 provider 的定位不只是状态管理,这只是它的一个模块。
其他的功能对于状态管理来说,注解,各种 provider,他们很灵活,但是意味着更容易出错,更不知道在什么情况下用哪种 provider 最合适。随地大小注解声明一堆 state,以及 provider 里面还可以 ref 嵌套,这种写法过于黑盒,不稳定性极高,修改一个 provider,你不知道会有其他的 provider 也受到了影响。
riverpod 默认是根据 provider 入参的 == + hashCode 判断 Notifier 的 唯一性,一般入参都会用 freezed 重写 ==和 hashCode. 这样依赖入参其实不太灵活,有的时候我们只想用一个 String id 来标记。
ProviderArg
用 ProviderArg 来包装 key 和 arg,用 key 来重写其 == 和 hascode。key 和 arg 分离,灵活性提高。保证 key 唯一,那么就可以方便的复用 ViewModel 实例。在任何地方通过 key 获取到已经存在的实例
@immutable
class ProviderArg<T extends Object> {
final String? key;
final dynamic arg;
T get requireArg {
return arg as T;
}
final Object _defaultKey = "ProviderKey(${DateTime.now().millisecondsSinceEpoch})_${const Uuid().v6()}";
static const _uniqueKey = "ProviderArg#uniqueKey";
Object get _key {
return key ?? _defaultKey;
}
factory ProviderArg.unique({T? arg}) {
return ProviderArg(key: _uniqueKey, arg: arg);
}
ProviderArg({
this.key,
this.arg,
});
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other is ProviderArg && runtimeType == other.runtimeType && _key == other._key);
}
@override
int get hashCode {
return _key.hashCode;
}
@override
String toString() {
return 'ProviderKey{key: $_key}';
}
}
typedef ProviderBuilder<VM extends ViewModel<S>, S, T extends Object>
= AutoDisposeStateNotifierProviderFamily<VM, S, ProviderArg<T>>;
ProviderBuilder<VM, S, T> buildProvider<VM extends ViewModel<S>, S, T extends Object>({
required VM Function(ProviderArg<T> key) viewModel,
}) {
return StateNotifierProvider.autoDispose.family<VM, S, ProviderArg<T>>((ref, key) {
return viewModel.call(key);
});