.family
Avant de lire ceci, pensez à vous renseigner sur les providers et comment les lires.
Dans cette partie, nous allons parler en détail du modificateur de provider .family.
Le modifieur .family a un seul but : Créer un provider à partir de valeurs externes.
Certains cas d'utilisation communs pour family seraient :
- Combinaison de FutureProvider avec .familypour récupérer unMessageà partir de son ID.
- Passer Localeà un provider, afin que nous puissions gérer les traductions (translations):
Usage
Le fonctionnement des familles consiste à ajouter un paramètre supplémentaire au provider. Ce paramètre peut ensuite être utilisé librement dans notre provider pour créer un état.
Par exemple, nous pourrions combiner family avec FutureProvider pour
récupérer Message à partir de son ID :
final messagesFamily = FutureProvider.family<Message, String>((ref, id) async {
  return dio.get('http://my_api.dev/messages/$id');
});
Ensuite, lorsque on utilise notre provider messagesFamily, la syntaxe est légèrement modifiée.
La syntaxe habituelle ne fonctionnera plus :
Widget build(BuildContext context, WidgetRef ref) {
  // Erreur – messagesFamily n'est pas un provider
  final response = ref.watch(messagesFamily);
}
A la place, nous devons passer un paramètre à messagesFamily :
Widget build(BuildContext context, WidgetRef ref) {
  final response = ref.watch(messagesFamily('id'));
}
Il est possible d'utiliser une famille avec différents paramètres simultanément.  Par exemple, on peut utiliser un titleFamily pour lire
à la fois les traductions française et anglaise en même temps :
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');
}
Restrictions sur les paramètres
Pour que les familles fonctionnent correctement, il est essentiel que le paramètre
passé à un provider ait un hashCode et un == cohérents.
Idéalement, le paramètre devrait être soit une primitive (bool/int/double/String),
une constante (providers), ou un objet immuable qui surcharge (overrid) == et hashCode.
PRÉFÉRER Utilisation de autoDispose lorsque le paramètre n'est pas constant :
Vous pouvez vouloir utiliser les familles pour transmettre la saisie d'un champ de recherche à votre provider. Mais cette valeur peut changer souvent et ne jamais être réutilisée. Cela pourrait provoquer des fuites de mémoire car, par défaut, un provider n'est jamais détruit même s'il n'est plus utilisé.
Utiliser à la fois .family et .autoDispose corrige cette fuite de mémoire :
final characters = FutureProvider.autoDispose.family<List<Character>, String>((ref, filter) async {
  return fetchCharacters(filter: filter);
});
Passage de plusieurs paramètres à une famille
Les familles n'ont pas de support intégré (built-in) pour transmettre plusieurs valeurs à un provider.
D'autre par contre, cette valeur peut être n'importe quoi (pour autant qu'elle respecte les restrictions mentionnées précédemment).
Cela inclut :
- Le tuple de tuple.
- Les objets générés avec Freezed ou built_value.
- les objets utilisant equatable.
voici un example en utilisant Freezed et 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);
  // Faire quelque chose avec userId/locale.
});
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // Lire le user ID de quelque part
  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);
  // Faire quelque chose avec userId/locale.
});
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // Lire le user ID de quelque part
  final locale = Localizations.localeOf(context);
  final something = ref.watch(
    exampleProvider(MyParameter(userId: userId, locale: locale)),
  );
  ...
}