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


相关推荐
0wioiw02 小时前
Flutter基础(FFI)
flutter
Georgewu9 天前
【HarmonyOS 5】鸿蒙跨平台开发方案详解(一)
flutter·harmonyos
爱吃鱼的锅包肉9 天前
Flutter开发中记录一个非常好用的图片缓存清理的插件
flutter
张风捷特烈10 天前
每日一题 Flutter#13 | build 回调的 BuildContext 是什么
android·flutter·面试
恋猫de小郭10 天前
Flutter 又双叒叕可以在 iOS 26 的真机上 hotload 运行了,来看看又是什么黑科技
android·前端·flutter
QC七哥10 天前
跨平台开发flutter初体验
android·flutter·安卓·桌面开发
小喷友11 天前
Flutter 从入门到精通(水)
前端·flutter·app
恋猫de小郭11 天前
Flutter 里的像素对齐问题,深入理解为什么界面有时候会出现诡异的细线?
android·前端·flutter
tbit11 天前
dart私有命名构造函数的作用与使用场景
flutter·dart