跳到主要内容

.family

在阅读本文之前,请考虑阅读有关 providers 的内容以及 如何读取provider。 在本部分中,我们将详细讨论.family修饰符。

.family 修饰符有一个目的:根据外部参数获取唯一的provider。

比如family的一些常用的使用场景:

  • 结合 FutureProvider.family 通过它的ID来获取一条 消息
  • 将当前 区域 传递给provider,以便让我们可以处理翻译相关的内容。

用法

family的工作方式是向provider添加一个额外的参数。 然后可以在我们的provider中自由地使用这个参数来创建一些状态。

比如说,我们可以组合 familyFutureProvider 通过它的ID来获取一条 消息

final messagesFamily = FutureProvider.family<Message, String>((ref, id) async {
return dio.get('http://my_api.dev/messages/$id');
});

在使用 messagesFamily provider时,语法略有不同。
通常的语法将不能使用:

Widget build(BuildContext context, WidgetRef ref) {
// Error – messagesFamily is not a provider
final response = ref.watch(messagesFamily);
}

相反,我们需要将一个参数传递给 messagesFamily

Widget build(BuildContext context, WidgetRef ref) {
final response = ref.watch(messagesFamily('id'));
}
信息

可以同时使用具有不同参数的 family。
比如,我们可以使用titleFamily同时读取法语和英语的翻译:


Widget build(BuildContext context, WidgetRef ref) {
final frenchTitle = ref.watch(titleFamily(const Locale('fr')));
final englishTitle = ref.watch(titleFamily(const Locale('en')));

return Text('fr: $frenchTitle en: $englishTitle');
}

参数限制

为了让family正常工作,传递给provider的参数必须具有一致的 hashCode==

理想情况下,参数应该是基础类型(bool/int/double/String)、常量(providers)或重载 ==hashCode 的不可变对象。

当参数不是常量时最好使用autoDispose:

你可能希望使用family将搜索内容传递给你的provider。 但是这个值经常会改变,并且永远不会被重用。
这可能会导致内存泄漏,因为默认情况下,即使不再使用provider也不会销毁。

同时使用 .family.autoDispose 可以解决内存泄漏的问题:

final characters = FutureProvider.autoDispose.family<List<Character>, String>((ref, filter) async {
return fetchCharacters(filter: filter);
});

将多个参数传递给family

family不支持将多个值传递给provider。

On the other hand, that value could be anything (as long as it matches with the restrictions mentioned previously). 另一方面,该值可以是任何东西(只要它在前面提到的限制当中)。

这包括:

下面是使用 Freezedequatable 来传递多个参数的示例:


abstract class MyParameter with _$MyParameter {
factory MyParameter({
required int userId,
required Locale locale,
}) = _MyParameter;
}

final exampleProvider = Provider.autoDispose.family<Something, MyParameter>((ref, myParameter) {
print(myParameter.userId);
print(myParameter.locale);
// Do something with userId/locale
});


Widget build(BuildContext context, WidgetRef ref) {
int userId; // Read the user ID from somewhere
final locale = Localizations.localeOf(context);

final something = ref.watch(
exampleProvider(MyParameter(userId: userId, locale: locale)),
);

...
}