快速开始
译者注:在此章节中,由于 Provider 库,Provider 类,Provider 及其相关的提供者程序类容易造成混淆,一般的,我们约定:
- Provider 库 ->
pkg:Provider
/Provider
,和 Riverpod 一样首字母大写。 - Provider 类 ->
provider
,小写,特指单纯的提供者程序类 Provider。 - Provider 泛指 ->
提供者程序
,表示各种不同的提供者程序类都适用。
其他地方的代指某个 provider,会被具体翻译,避免不必要的误解,请放心阅读。
如有翻译错误还请 pr 指正。
本部分专为熟悉 Provider 包并希望了解 Riverpod 的人员而设计。
首先,请阅读简短的入门指南文章,并尝试使用小型沙盒示例来测试 Riverpod 的功能。 如果您喜欢那里看到的内容,那么您应该明确考虑迁移。
事实上,从 Provider 迁移到 Riverpod 可以非常简单。
迁移基本上包括几个步骤,这些步骤可以以增量方式完成。
从 ChangeNotifierProvider
开始
在过渡到 Riverpod 时是可以的继续使用,而不是尽快使用 ChangeNotifier
其最新的花哨功能。
事实上,可以从以下几点着手开始:
// 如果你有这个……
class MyNotifier extends ChangeNotifier {
int state = 0;
void increment() {
state++;
notifyListeners();
}
}
// ……只需要加上这个!
final myNotifierProvider = ChangeNotifierProvider<MyNotifier>((ref) {
return MyNotifier();
});
正如你所看到的,Riverpod 公开了一个 ChangeNotifierProvider 类, 该类正是为了支持从 pkg:Provider 迁移。
请记住,在编写新代码时不建议使用 ChangeNotifierProvider
,因为它不是使用 Riverpod 的最佳方式,
但它是开始迁移的一种温和且非常简单的方法。
不要急于立即尝试将您的 ChangeNotifier
迁移到更现代的 Riverpod 的提供者程序。
有些地方会进行一些泛型的转变,因此最初可能很难做到。
慢慢来,因为首先熟悉 Riverpod 很重要; 你很快就会发现,几乎所有来自 pkg:provider 的提供者程序在 pkg:riverpod 中都有严格等价的代码。
从叶子开始
从不依赖于其他任何内容的提供者程序开始,即从依赖项树中的叶子开始。
迁移完所有叶子后,可以转到依赖于叶子的提供者程序。
换言之,首先要避免迁移 ProxyProvider
;当迁移了它们的所有依赖项,就可以开始处理它们了。
这应该促进和简化迁移过程,同时还可以最大限度地减少/跟踪任何错误。
Riverpod 和 Provider 可以共存
请记住,完全可以同时使用 Provider 和 Riverpod。
事实上,使用导入别名,可以同时使用两个 API 了。
这也非常有助于提高可用性,并消除了任何模棱两可的 API 用法。
如果计划执行此操作,请考虑对代码库中的每个提供者程序导入使用导入别名。
关于如何有效实现导入别名的完整指南即将发布。
您不必立即使用 Consumer
请务必记住,无需立即使用 Riverpod 的 Consumer
API。
如果您刚刚开始迁移,如上所述,您可能应该从 ChangeNotifierProvider
开始。
考虑上面定义的 myNotifierProvider
。
由于您的内部代码可能依赖于 pkg:Provider 的 API,因此请使用以下代码开始使用 pkg:Riverpod 的 ChangeNotifier
。
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: ref.watch(myNotifierProvider.notifier)),
]
)
这样,最初只需将根 Widget 转换为 ConsumerWidget
。
这应该会进一步简化向 pkg:Riverpod 的迁移。
一次迁移一个提供者程序
如果您已有应用,请不要尝试一次迁移所有的提供者程序!
虽然从长远来看,您应该努力将所有应用程序迁移到 Riverpod,但不要让自己筋疲力尽。
一次只迁移一个提供者程序。
以上面的例子为例。将其 myNotifierProvider
完全迁移到 Riverpod 意味着需要编写以下内容:
class MyNotifier extends Notifier<int> {
int build() => 0;
void increment() => state++;
}
final myNotifierProvider = NotifierProvider<MyNotifier, int>(MyNotifier.new);
……并且还需要更改这个 myNotifierProvider
的使用方式,即每个 context.watch
的位置替换为 ref.watch
。
此操作可能需要一些时间,并可能导致一些错误,因此不要急于一次完成所有操作。
迁移 ProxyProvider
在 pkg:Provider 中,ProxyProvider
用于组合来自其他提供者程序的值;
它的构建被动地取决于其他提供者程序的价值。
相反,在 Riverpod 中,提供者程序默认是可组合的;
因此,在迁移 ProxyProvider
时,如果要声明从一个提供者程序到另一个提供者程序的直接依赖项,则只需编写 ref.watch
即可。
如果有的话,将值与 Riverpod 相结合应该感觉更简单明了;因此,迁移应该大大简化代码。
此外,将两个以上的提供者程序组合在一起没有任何障碍:只需添加另一个 ref.watch
,就可以了。
预先初始化
由于 Riverpod 的提供者程序是全局 final 变量,因此它们默认是懒加载的。
如果您需要在启动时初始化一些预热数据或有用的服务,
最好的做法是首次读取提供者程序的时候,您手动去设置 MultiProvider
。
换句话说,由于 Riverpod 不能被强制预先初始化,因此可以在启动阶段读取和缓存它们, 以便在应用程序的其余部分需要时它们完成了初始化并准备就绪。
有关 pkg:Riverpod 提供者程序的快速初始化的完整指南 [可在此处获得]。
代码生成
建议使用代码生成,以便以面向未来的方式使用 Riverpod。
顺便说一句,当元编程成为现实的时候,代码生成很可能是 Riverpod 的默认代码。
不幸的是, @riverpod
无法为 ChangeNotifierProvider
生成代码。
要解决此问题,您可以使用以下实用程序扩展方法:
extension ChangeNotifierWithCodeGenExtension on Ref {
T listenAndDisposeChangeNotifier<T extends ChangeNotifier>(T notifier) {
notifier.addListener(notifyListeners);
onDispose(() => notifier.removeListener(notifyListeners));
onDispose(notifier.dispose);
return notifier;
}
}
然后,您可以使用以下代码生成语法公开您的 ChangeNotifier
:
// ignore_for_file: unsupported_provider_value
MyNotifier example(Ref ref) {
return ref.listenAndDisposeChangeNotifier(MyNotifier());
}
完成“基本”迁移后,您可以将 ChangeNotifier
更改为 Notifier
,从而消除了临时扩展的需要。
以前面的示例为例,“完全迁移” Notifier
变为:
class MyNotifier extends _$MyNotifier {
int build() => 0;
void increment() => state++;
}
一旦完成此操作,并且您确信代码库中不再有 ChangeNotifierProvider
,您就可以彻底摆脱临时扩展。
请记住,虽然是推荐的,但代码生成不是强制性的。
以增量方式进行迁移是个好的选择:
如果您觉得在一次转换到代码生成语法的同时实现此迁移可能太麻烦了,别勉强。
按照本指南,您可以稍后做进一步的迁移到代码生成。