[译][官方文档] 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 规则。然后,前面的代码片段就会提示警告。查看 开始 了解安装步骤。


相关推荐
比格丽巴格丽抱5 小时前
flutter项目苹果编译运行打包上线
flutter·ios
SoaringHeart5 小时前
Flutter进阶:基于 MLKit 的 OCR 文字识别
前端·flutter
AiFlutter9 小时前
Flutter通过 Coap发送组播
flutter
嘟嘟叽1 天前
初学 flutter 环境变量配置
flutter
iFlyCai1 天前
深入理解Flutter生命周期函数之StatefulWidget(一)
flutter·生命周期·dart·statefulwidget
sunly_1 天前
Flutter:photo_view图片预览功能
android·javascript·flutter
Summer不秃2 天前
Flutter中sqflite的使用案例
flutter
sunly_2 天前
Flutter:TweenAnimationBuilder自定义隐式动画
flutter
AiFlutter2 天前
Flutter-Web首次加载时添加动画
前端·flutter
Allen Su2 天前
【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存
flutter·缓存·如何清除指定网络图片的缓存·网络图片缓存