mcpField
R
riverpod-from-provider

riverpod-from-provider

github.com/serverpod开发1065 次安装34 周前更新
代码仓库

关于 riverpod-from-provider

面向 Flutter 开发者的 Provider 到 Riverpod 迁移指南,介绍分步迁移、API 变化及常见 Provider 模式的替换方式。

主要功能

  1. 01分阶段迁移指导
  2. 02Provider 与 Riverpod 并用
  3. 03ChangeNotifier 迁移路径
  4. 04使用 ref.watch 组合 Provider
  5. 05参数化与自动销毁状态
  6. 06通过覆盖项进行测试

适用场景

  1. 01分阶段迁移 Provider 应用
  2. 02替换 ProxyProvider 依赖
  3. 03管理各参数对应的状态
  4. 04在测试中模拟 Provider

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/serverpod/skills-registry --skill riverpod-from-provider

安装后在 Claude Code 中输入/riverpod-from-provider确认已加载。

详细介绍

Riverpod — 从 Provider 迁移

动机

Riverpod 作为 Provider 的后继方案而创建,旨在解决 InheritedWidget 的局限:

  • 相同类型: Provider 不能在树中存在两个 Provider<Item>(只能找到最近的一个)。Riverpod 没有此限制;Provider 通过变量而非类型来标识。
  • 组合 Provider: ProxyProvider 繁琐且容易出错。在 Riverpod 中,可在 Provider 内使用 ref.watch 依赖其他 Provider;组合起来很简单。
  • AsyncValue: Riverpod 在加载时可以提供先前的数据(例如,显示旧列表和加载指示器)。Provider 无法简洁地实现这一点。
  • 安全性: Provider 可能在运行时抛出 ProviderNotFoundException。Riverpod 从设计上避免了这种情况。
  • 释放: 当使用者停止监听时,Provider 无法做出响应;作用域管理也很棘手。Riverpod 提供 autoDispose 和 ref.keepAlive,以便清晰地管理生命周期和缓存。
  • 参数: Riverpod 的 .family 提供类型安全、带参数的 Provider,并为每个参数维护独立状态;配合 autoDispose,未使用的状态会被释放。在 Provider 中很难实现等效功能。
  • 测试: 使用 Provider 时,必须为每个测试重新定义 Provider。使用 Riverpod 时,可通过 overrides 覆盖 Provider 以进行模拟。
  • 副作用: Riverpod 提供 ref.listen,用于响应更改(例如导航、弹出提示栏)。Provider 没有内置的等效功能。

主要 API 变更:使用 ConsumerWidget(和 WidgetRef)代替 StatelessWidget,并使用 ref.watch / ref.read 代替 context.watch / context.read。


快速入门

  • 阅读 Riverpod 入门指南(riverpod-getting-started)并尝试一个小示例。
  • 逐步迁移。Provider 和 Riverpod 可以并行运行(必要时使用导入别名)。
从 ChangeNotifierProvider 开始

保留现有的 ChangeNotifier 类,并使用 Riverpod 的 ChangeNotifierProvider 对其进行包装:

final myNotifierProvider = ChangeNotifierProvider<MyNotifier>((ref) => MyNotifier());

在根节点使用 ProviderScope。在使用此 Provider 的位置(例如 ConsumerWidget 中),将 context.watch 替换为 ref.watch。无需立即将所有 ChangeNotifier 转换为 Notifier。

从叶子节点开始

先迁移没有依赖项的 Provider(即“叶子节点”),然后再迁移依赖于它们的 Provider。在依赖项迁移完成之前,避免迁移 ProxyProvider。

一次迁移一个 Provider

每次迁移并测试一个 Provider。完全迁移一个 ChangeNotifier 意味着:(1) 将其转换为 Notifier + NotifierProvider;(2) 将所有用于它的 context.watch 替换为 ref.watch。

ProxyProvider → ref.watch

在 Riverpod 中,通过在另一个 Provider 内使用 ref.watch 来组合 Provider:

final labelProvider = Provider<String>((ref) {
  final userIdNotifier = ref.watch(userIdNotifierProvider);
  return 'The user ID is ${userIdNotifier.userId}';
});

对于有状态的组合对象(例如 ChangeNotifierProxyProvider),可在 Provider 中使用 ref.listen,以响应另一个 Provider 的变化并更新你的 notifier。

提前初始化

Riverpod Provider 默认采用惰性加载。若要在启动时预热数据,可在根节点监听该 Provider(例如,在 ProviderScope 下使用一个 Consumer,并将你的应用作为子项返回)。请参阅 riverpod-eager-initialization。

代码生成

代码生成不会生成 ChangeNotifierProvider。迁移期间,你可以使用一个小型扩展(listenAndDisposeChangeNotifier),通过 @riverpod 暴露 ChangeNotifier;切换到 Notifier 后,再移除此扩展。代码片段请参阅官方快速入门。


Provider 与 Riverpod 对比

定义 Provider
  • Provider: Provider 是 Widget(例如,位于 MultiProvider 中)。
  • Riverpod: Provider 是顶层的 final 变量。定义 Provider 不需要 Widget 树。在应用根节点添加 ProviderScope。
读取
  • Provider: context.watch<T>()、context.read<T>()、context.select<T,R>(...)。
  • Riverpod: 使用 ConsumerWidget(或 Consumer)获取 WidgetRef ref;然后使用 ref.watch(provider)、ref.read(provider)、ref.watch(provider.select(...))。
  • 在 build 中使用 watch,在事件处理程序中使用 read。这与 Provider 的思维模型相同。
Consumer

Riverpod 提供了 Consumer,其参数为 (context, ref, child)。无需使用 Consumer2、Consumer3 等:只需在一个 builder 中多次调用 ref.watch。

作用域与 family + autoDispose

Provider 使用作用域来销毁状态或实现每个页面独立的状态。在 Riverpod 中:

  • autoDispose 会在没有监听器时销毁状态(ref.onCancel / ref.onDispose)。
  • .family 会创建带参数的 Provider(每个参数对应一个状态)。与 autoDispose 搭配使用可避免缓存无限增长。

因此:使用 .family 实现“每个 X 对应一个状态”,使用 .autoDispose 实现“未使用时销毁”,而不是使用作用域。

详情请参阅 riverpod-getting-started、riverpod-providers、riverpod-family 和 riverpod-auto-dispose。

评论

支持 Markdown