[译][官方文档] Flutter/Dart 状态管理库 Riverpod (八)- 概要 - 向请求传递参数

原文链接:Passing arguments to your requests | Riverpod

pub:riverpod | Dart Package (flutter-io.cn)

译时版本: 2.4.9


之前翻译过 Riverpod 的官方文档,现在随着版本更新,官方文档又多了很多新内容,所以再补充翻译一下。

之前翻译过的内容,现在官方文档有中文了。
Flutter状态管理库Riverpod官方文档翻译汇总 - 掘金 (juejin.cn)


向请求传递参数

在前面的文章中,看到了如何定义 "provider" 创建简单的 GET HTTP 请求。

不过通常 HTTP 请求需要外部参数。

例如,前面使用了 Bored API 给用户一个随机 activity 。 但是用户可能想要过滤 activity 的类型或确认所需价格等。。。

这些参数不可能提前预知。所以需要从 UI 向 provider 传递这些参数。

修改 provider 以接收参数

提醒一下,前面如下定义了 provider :

dart 复制代码
// "函数式" provider  
@riverpod  
Future<Activity> activity(ActivityRef ref) async {  
// TODO: 执行网络请求获取 activity
return fetchActivity();  
}  
  
// 或 替代方案,"notifier"  
@riverpod  
class ActivityNotifier2 extends _$ActivityNotifier2 {  
    /// Notifier 参数在 build 方法里指定。
    /// 可以指定任意多个,使用任意名字,甚至是可选/被命名的。
    @override  
    Future<Activity> build(String activityType) async {  
    // 参数也能用于 "this.<argumentName>"  
    print(this.activityType);  

    // TODO: 执行网络请求获取 activity
    return fetchActivity();  
    }  
}

要传递参数给 provider ,只需为被注解的函数添加参数即可。

例如,将 provider 改为接收一个 String 参数,该参数对应所需的 activity 的类型:

dart 复制代码
@riverpod
Future<Activity> activity(
  ActivityRef ref,
  // 向 provider 添加参数。
  // 参数的类型可任意。
  String activityType,
) async {
  // 这里就能使用 "activityType" 来构建 URL 。
  // 它会指向 "https://boredapi.com/api/activity?type=<activityType>"
  final response = await http.get(
    Uri(
      scheme: 'https',
      host: 'boredapi.com',
      path: '/api/activity',
      // 无需手动编码查询参数,"URI" 类会自动处理。
      queryParameters: {'type': activityType},
    ),
  );
  final json = jsonDecode(response.body) as Map<String, dynamic>;
  return Activity.fromJson(json);
}

警告

向 provider 传递参数时,非常建议将启用 provider 的 "autoDispose" 。

"autoDispose" 失败的话可能会导致内存泄漏。

查看 清空缓存和响应状态清理 了解更多详细内容。

修改 UI 以传递参数

前面组件是如下消费 provider :

dart 复制代码
AsyncValue<Activity> activity = ref.watch(activityProvider);

但是现在 provider 要接收参数,所以消费它的语法略有不同。

provider 现在是函数,需要用请求的参数调用。

可以如下修改 UI 以传递一个硬编码的 activity 类型:

dart 复制代码
AsyncValue<Activity> activity = ref.watch(
  // provider 现在是函数,接收 activity 类型。
  // 简单起见,现在传递一个常量字符串。
  activityProvider('recreational'),
);

传递给 provider 的参数对应着除 "ref" 之外被注解的函数的参数。

信息

同时监听带有不同参数值的同一个 provider 是完全可能的。 例如,UI 可以同时渲染 "recreational" "cooking" 的 activity 。

dart 复制代码
return Consumer(
  builder: (context, ref, child) {
    final recreational = ref.watch(activityProvider('recreational'));
    final cooking = ref.watch(activityProvider('cooking'));

    // 可以同时渲染 activity 。
    // 两个请求会并行发生并能被正确地缓存。
    return Column(
      children: [
        Text(recreational.valueOrNull?.activity ?? ''),
        Text(cooking.valueOrNull?.activity ?? ''),
      ],
    );
  },
);

缓存考量和参数约束

向 provider 传递参数时,计算也会缓存。区别是计算会为每个参数值缓存。

这意味着如果两个组件消费相同参数值的同一个 provider ,只会发送单次网络请求。

但是如果两个组件消费不同参数值的同一个 provider ,则会发送两次网络请求。

这种实现,Riverpod 是依靠参数的 == 操作符。

因此,向 provider 传递的参数保持完全等同是很重要的。

警告

一个常见错误是直接初始化一个新对象作为 provider 的参数,但该对象没有覆写 == 。 例如,可能想如下传递一个 List (列表):

csharp 复制代码
// 可以修改 activityProvider 接收一个字符串列表。  
// 然后在直接 watch 调用里直接创建列表。  
ref.watch(activityProvider(['recreational', 'cooking']));

该代码的问题是 ['recreational', 'cooking'] == ['recreational', 'cooking']false 的。因此,Riverpod 会认为两个参数值是不同的,就会尝试发送新的网络请求。

这会导致网络请求的无限循环,会一直向用户显示进程指示器(转圈圈)。

要修改该问题,应该使用 const 列表(const ['recreational', 'cooking']),或者使用覆写了 == 操作符的自定义列表。

想要及时发现该错误,建议使用 riverpod_lint 和开启 provider_parameters lint 规则。然后,前面的代码片段就会提示警告。查看 开始 了解安装步骤。


相关推荐
m0_7482478011 小时前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
迷雾漫步者13 小时前
Flutter组件————PageView
flutter·跨平台·dart
迷雾漫步者20 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
coder_pig1 天前
📝小记:Ubuntu 部署 Jenkins 打包 Flutter APK
flutter·ubuntu·jenkins
捡芝麻丢西瓜1 天前
flutter自学笔记5- dart 编码规范
flutter·dart
恋猫de小郭1 天前
什么?Flutter 可能会被 SwiftUI/ArkUI 化?全新的 Flutter Roadmap
flutter·ios·swiftui
sunly_2 天前
Flutter:导航,tab切换,顶部固定,列表分页滚动
开发语言·javascript·flutter
敲代码的小强2 天前
Flutter项目兼容鸿蒙Next系统
flutter·华为·harmonyos
Zh-jie3 天前
flutter 快速实现侧边栏
前端·javascript·flutter
truemi.733 天前
flutter --no-color pub get 超时解决方法
android·flutter