.family
在阅读本文之前,请考虑阅读有关 providers 的内容以及 如何读取provider。
在本部分中,我们将详细讨论.family修饰符。
.family  修饰符有一个目的:根据外部参数获取唯一的provider。
比如family的一些常用的使用场景:
- 结合 FutureProvider 和 .family通过它的ID来获取一条消息。
- 将当前 区域传递给provider,以便让我们可以处理翻译相关的内容。
用法
family的工作方式是向provider添加一个额外的参数。 然后可以在我们的provider中自由地使用这个参数来创建一些状态。
比如说,我们可以组合 family 和 FutureProvider 通过它的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). 另一方面,该值可以是任何东西(只要它在前面提到的限制当中)。
这包括:
- 一个元组 tuple
- 使用Freezed 或 built_value 生成的对象
- 使用 equatable 的对象
下面是使用 Freezed 或 equatable 来传递多个参数的示例:
- Freezed
- Equatable
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)),
  );
  ...
}
class MyParameter extends Equatable  {
  MyParameter({
    required this.userId,
    required this.locale,
  });
  final int userId;
  final Locale locale;
  
  List<Object> get props => [userId, locale];
}
final exampleProvider = Provider.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)),
  );
  ...
}