diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args.mdx
index aa0146c63..f1e3673d8 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args.mdx
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args.mdx
@@ -1,5 +1,5 @@
---
-title: Passing arguments to your requests
+title: 将参数传递给您的请求
version: 1
---
@@ -15,33 +15,58 @@ import multipleConsumerFamily from "!!raw-loader!./passing_args/raw/multiple_con
import tupleFamily from "!!raw-loader!./passing_args/raw/tuple_family.dart";
import consumerTupleFamily from "!!raw-loader!./passing_args/raw/consumer_tuple_family.dart";
+
+在上一篇文章中,我们看到了如何定义一个“provider”来发出一个简单的 _GET_ HTTP 请求。
+但通常,HTTP 请求依赖于外部参数。
+
+例如,以前我们使用 [Bored API](https://boredapi.com/) 向用户推荐随机活动。
+但也许用户想要过滤他们想做的活动类型,或者有价格要求,等等……
+这些参数事先是未知的。因此,我们需要一种方法将这些参数
+从我们的 UI 传递到我们的提供程序。
+
+## 更新我们的提供者程序以接受参数
+
+提醒一下,以前我们是这样定义我们的提供程序的:
+
+当不依赖于代码生成时,我们需要稍微调整定义提供程序的语法,以支持传递参数。
+这是通过依靠称为“family”的“修饰符”来完成的。
+
+简而言之,我们需要在提供程序的类型之后添加 `.family` 一个额外的类型参数,
+以及与参数类型相对应的类型参数。
+例如,我们可以更新提供程序以接受与所需活动类型相对应的 String 参数:
@@ -49,110 +74,191 @@ corresponding to the type of activity desired:
+
+要将参数传递给我们的提供程序,我们只需在带注解的函数本身上添加参数即可。
+例如,我们可以更新提供程序以接受与所需活动类型相对应的 `String` 参数:
:::caution
+
+将参数传递给提供程序时,强烈建议在提供程序上启用“autoDispose”。
+否则可能会导致内存泄漏。
+有关详细信息,请参阅。
:::
+
+## 更新我们的 UI 以传递参数
+
+以前,小部件是这样消费我们的提供程序的:
+
+但是现在我们的提供程序收到参数,使用它的语法略有不同。
+提供程序现在是一个函数,需要使用请求的参数来调用它。
+我们可以更新我们的 UI 以传递硬编码类型的活动,如下所示:
+
+传递给提供程序的参数对应于带注解的函数的参数,减去“ref”参数。
:::info
+
+完全可以同时侦听具有不同参数的同一提供程序。
+例如,我们的 UI 可以同时呈现“娱乐(recreational)”_和_“烹饪(cooking)”活动:
+
+这就是修饰符被称为“family”的原因:
+因为把参数传递给提供程序(译者注:作为不同状态的区分的 key 值),
+可以有效地将提供程序转换为一组具有相同逻辑的状态。
:::
+
+## 缓存注意事项和参数限制
+
+将参数传递给提供程序时,仍会缓存计算。
+不同之处在于,计算现在是按参数缓存的。
+
+这意味着,如果两个小部件使用具有相同参数的同一提供程序,则只会发出单个网络请求。
+但是,如果两个小部件使用具有不同参数的同一提供程序,则将发出两个网络请求。
+
+为此,Riverpod 依赖于参数的 `==` 运算符。
+因此,传递给提供程序的参数必须具有一致的相等性,这一点很重要。
:::caution
+
+一个常见的错误是直接实例化一个新对象作为提供程序的参数,但该对象没有重写 `==`。
+例如,您可能很想去这样使用 `List`:
+
+此代码的问题在于 `['recreational', 'cooking'] == ['recreational', 'cooking']` 的结果是 `false`。
+因此,Riverpod 将认为这两个参数不同,并尝试发出新的网络请求。
+这将导致网络请求的无限循环,一直向用户显示进度指示器。
+
+要解决此问题,您可以使用 `const` 列表 (`const ['recreational', 'cooking']`)
+或使用重写了 `==` 的自定义列表实现。
+
+为了帮助发现此错误,建议使用 [riverpod_lint](https://pub.dev/packages/riverpod_lint)
+并启用 [provider_parameters](https://github.com/rrousselGit/riverpod/tree/master/packages/riverpod_lint#provider_parameters)
+的 lint 规则。这样做之后,上面的代码片段将显示警告。
+有关安装步骤,请参阅。
:::
+
+考虑到这一点,您可能想知道如何将多个参数传递给提供程序。
+建议的解决方案是:
+
+- 切换到代码生成,这样可以传递任意数量的参数
+- 使用 Dart 3 的记录 (record) 语法
+
+Dart 3 的记录之所以派上用场,是因为它们自然覆盖 `==` 并具有方便的语法。
+例如,我们可以更新我们的提供商,以同时接受一种活动类型和最高价格:
+
+然后,我们可以像这样消费这个提供程序:
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/family.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/family.dart
index 12168d573..d9e7b0ff2 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/family.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/family.dart
@@ -9,18 +9,18 @@ part 'family.g.dart';
@riverpod
Future activity(
ActivityRef ref,
- // We can add arguments to the provider.
- // The type of the parameter can be whatever you wish.
+ // 我们可以向提供者添加参数。
+ // 参数的类型可以是您想要的任何类型。
String activityType,
) async {
- // We can use the "activityType" argument to build the URL.
- // This will point to "https://boredapi.com/api/activity?type="
+ // 我们可以使用“activityType”参数来构建 URL。
+ // 这将指向 "https://boredapi.com/api/activity?type="
final response = await http.get(
Uri(
scheme: 'https',
host: 'boredapi.com',
path: '/api/activity',
- // No need to manually encode the query parameters, the "Uri" class does it for us.
+ // 无需手动编码查询参数,“Uri”类为我们完成了这一工作。
queryParameters: {'type': activityType},
),
);
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/provider.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/provider.dart
index 2c25b5680..71c45fd98 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/provider.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/codegen/provider.dart
@@ -9,24 +9,24 @@ part 'provider.g.dart';
FutureOr fetchActivity() => throw UnimplementedError();
/* SNIPPET START */
-// A "functional" provider
+// “函数型”提供商
@riverpod
Future activity(ActivityRef ref) async {
- // TODO: perform a network request to fetch an activity
+ // TODO: 执行网络请求以获取活动
return fetchActivity();
}
-// Or alternatively, a "notifier"
+// 或者替代方案,“通知者”
@riverpod
class ActivityNotifier2 extends _$ActivityNotifier2 {
- /// Notifier arguments are specified on the build method.
- /// There can be as many as you want, have any name, and even be optional/named.
+ /// 通知程序参数在构建方法上指定。
+ /// 可以有任意数量的通知程序参数,可以是任意的变量名称,甚至可以是可选/命名的参数。
@override
Future build(String activityType) async {
- // Arguments are also available with "this."
+ // 参数也可通过 "this." 使用
print(this.activityType);
- // TODO: perform a network request to fetch an activity
+ // TODO: 执行网络请求以获取活动
return fetchActivity();
}
}
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_family.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_family.dart
index 20077825d..4ad03dbcc 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_family.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_family.dart
@@ -13,8 +13,8 @@ class Example extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
/* SNIPPET START */
AsyncValue activity = ref.watch(
- // The provider is now a function expecting the activity type.
- // Let's pass a constant string for now, for the sake of simplicity.
+ // 提供者现在是一个需要活动类型的函数。
+ // 为了简单起见,我们现在传递一个常量字符串。
activityProvider('recreational'),
);
/* SNIPPET END */
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_list_family.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_list_family.dart
index ef70e4846..64433d625 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_list_family.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_list_family.dart
@@ -13,8 +13,8 @@ class Example extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
/* SNIPPET START */
- // We could update activityProvider to accept a list of strings instead.
- // Then be tempted to create that list directly in the watch call.
+ // 我们可以更新 ActivityProvider 接受字符串列表以替换之前的代码。
+ // 然后尝试直接在 watch 调用中创建该列表。
ref.watch(activityProvider(['recreational', 'cooking']));
/* SNIPPET END */
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_tuple_family.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_tuple_family.dart
index e4b5947ed..b63149bde 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_tuple_family.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/consumer_tuple_family.dart
@@ -12,9 +12,8 @@ class Example extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
/* SNIPPET START */
ref.watch(
- // Using a Record, we can pass our parameters.
- // It is fine to create the record directly
- // in the watch call as records override ==.
+ // 使用记录,我们可以传递参数。
+ // 在 watch 调用中,可以实现直接创建带有覆盖 == 功能的记录。
activityProvider((type: 'recreational', maxPrice: 40)),
);
/* SNIPPET END */
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/family.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/family.dart
index dece07b5b..f0ee5d47b 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/family.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/family.dart
@@ -8,35 +8,35 @@ FutureOr fetchActivity(String activityType) =>
throw UnimplementedError();
/* SNIPPET START */
-// A "functional" provider
+// “函数型”提供者
final activityProvider = FutureProvider.autoDispose
- // We use the ".family" modifier.
- // The "String" generic type corresponds to the argument type.
- // Our provider now receives an extra argument on top of "ref": the activity type.
+ // 我们使用 ".family" 修饰符。
+ // 泛型类型 "String" 对应于参数的类型。
+ // 我们的提供程序现在在 "ref" 上收到一个额外的参数:activity 的类型。
.family((ref, activityType) async {
- // TODO: perform a network request to fetch an activity using "activityType"
+ // TODO: 使用 "activityType" 执行网络请求以获取活动
return fetchActivity(activityType);
});
-// A "notifier" provider
+// “通知者”的提供者
final activityProvider2 = AsyncNotifierProvider.autoDispose
- // Again, we use the ".family" modifier, and specify the argument as type "String".
+ // 再次,我们使用 ".family" 修饰符,并将参数指定为 "String" 类型。
.family(
ActivityNotifier.new,
);
-// When using ".family" with notifiers, we need to change the notifier subclass:
+// 当将 ".family" 与通知程序一起使用时,我们需要更改通知程序子类:
// AsyncNotifier -> FamilyAsyncNotifier
// AutoDisposeAsyncNotifier -> AutoDisposeFamilyAsyncNotifier
class ActivityNotifier
extends AutoDisposeFamilyAsyncNotifier {
- /// Family arguments are passed to the build method and accessible with this.arg
+ /// Family 参数传递给构建方法并可通过 this.arg 访问
@override
Future build(String activityType) async {
- // Arguments are also available with "this.arg"
+ // 参数也可通过 "this.arg" 使用
print(this.arg);
- // TODO: perform a network request to fetch an activity
+ // TODO: 执行网络请求以获取活动
return fetchActivity(activityType);
}
}
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/multiple_consumer_family.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/multiple_consumer_family.dart
index 7cf928adb..68c9620db 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/multiple_consumer_family.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/multiple_consumer_family.dart
@@ -22,8 +22,8 @@ class Example extends ConsumerWidget {
final recreational = ref.watch(activityProvider('recreational'));
final cooking = ref.watch(activityProvider('cooking'));
- // We can then render both activities.
- // Both requests will happen in parallel and correctly be cached.
+ // 然后我们可以同时渲染这两个活动。
+ // 两个请求将并行发生并正确缓存。
return Column(
children: [
Text(recreational.valueOrNull?.activity ?? ''),
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/provider.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/provider.dart
index 254a71280..cdf67f173 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/provider.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/provider.dart
@@ -6,13 +6,13 @@ import '../../first_request/raw/activity.dart';
FutureOr fetchActivity() => throw UnimplementedError();
-// A "functional" provider
+// “函数型”提供商
final activityProvider = FutureProvider.autoDispose((ref) async {
- // TODO: perform a network request to fetch an activity
+ // TODO: 执行网络请求以获取活动
return fetchActivity();
});
-// Or alternatively, a "notifier"
+// 或者替代方案,“通知者”
final activityProvider2 = AsyncNotifierProvider(
ActivityNotifier.new,
);
@@ -20,7 +20,7 @@ final activityProvider2 = AsyncNotifierProvider(
class ActivityNotifier extends AsyncNotifier {
@override
Future build() async {
- // TODO: perform a network request to fetch an activity
+ // TODO: 执行网络请求以获取活动
return fetchActivity();
}
}
diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/tuple_family.dart b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/tuple_family.dart
index c39625d57..43840a881 100644
--- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/tuple_family.dart
+++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/essentials/passing_args/raw/tuple_family.dart
@@ -8,13 +8,12 @@ import 'package:http/http.dart' as http;
import '../../first_request/raw/activity.dart';
/* SNIPPET START */
-
-// We define a record representing the parameters we want to pass to the provider.
-// Making a typedef is optional but can make the code more readable.
+// 我们定义一条记录,表示我们想要传递给提供者的参数。
+// 创建 typedef 是可选的,但可以使代码更具可读性。
typedef ActivityParameters = ({String type, int maxPrice});
final activityProvider = FutureProvider.autoDispose
- // We now use the newly defined record as the argument type.
+ // 我们现在使用新定义的记录作为参数类型。
.family((ref, arguments) async {
final response = await http.get(
Uri(
@@ -22,7 +21,7 @@ final activityProvider = FutureProvider.autoDispose
host: 'boredapi.com',
path: '/api/activity',
queryParameters: {
- // Lastly, we can use the arguments to update our query parameters.
+ // 最后,我们可以使用参数来更新请求的查询参数。
'type': arguments.type,
'price': arguments.maxPrice,
},
diff --git a/website/src/documents_meta.js b/website/src/documents_meta.js
index 526516d78..3a1e3a739 100644
--- a/website/src/documents_meta.js
+++ b/website/src/documents_meta.js
@@ -65,7 +65,7 @@ export const documentTitles = {
"essentials/testing": "Testing your providers",
"essentials/side_effects": "执行副作用",
"essentials/provider_observer": "Logging and error reporting",
- "essentials/passing_args": "Passing arguments to your requests",
+ "essentials/passing_args": "将参数传递给您的请求",
"essentials/first_request": "开始你的第一次 provider/network 请求",
"essentials/faq": "FAQ",
"essentials/eager_initialization": "Eager initialization of providers",