Zum Hauptinhalt springen

.family

Bevor sie das lesen, sollten sie sich über Providers und Wie man sie ausließt informieren. In diesem Teil werden wir im Detail über den Provider-Modifikator .family sprechen.

Der .family-Modifikator hat einen Zweck: Einen Provider aus externen Werten zu erstellen.

Einige häufige Anwendungsfälle für family wären:

  • Kombination von FutureProvider mit .family, um eine Message anhand ihrer ID zu laden
  • Übergabe der aktuellen Locale an einen Provider, so dass wir mit Übersetzungen umgehen können:

Verwendung

Die family's funktionieren, indem sie dem Provider einen zusätzlichen Parameter hinzufügen. Dieser Parameter kann dann in unserem Provider frei verwendet werden, um einen Zustand zu erzeugen.

Zum Beispiel könnten wir family mit FutureProvider kombinieren, um eine Message anhand ihrer ID zu laden:

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

Bei der Verwendung unseres messagesFamily-Providers wird die Syntax dann leicht geändert.
Die übliche Syntax wird nicht mehr funktionieren

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

Stattdessen müssen wir einen Parameter an messagesFamily übergeben:

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

Es ist möglich, eine family mit verschiedenen Parametern gleichzeitig zu verwenden.
Zum Beispiel könnten wir eine titleFamily verwenden, um sowohl die französische als auch die englische Übersetzungen gleichzeitig zu lesen:

@override
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');
}

Parameter Einschränkungen

Damit family's korrekt funktionieren, ist es wichtig, dass der an einen Provider übergebene Parameter einen konsistenten hashCode und == haben muss.

Idealerweise sollte der Parameter entweder ein primitiver Datentyp (bool/int/double/String), eine Konstante (Provider) oder ein immutable Objekt, das == und hashCode überschreibt, sein.

BEVORZUGE die Benutzung von autoDispose wenn der Parameter keine Konstante ist:

Sie möchten vielleicht family's verwenden, um die Eingabe eines Suchfeldes an Ihren Provider zu übergeben. Dieser Wert kann sich jedoch häufig ändern und nie wieder verwendet werden.
Dies könnte zu Memory leaks führen, da ein Provider standardmäßig nie zerstört wird, selbst wenn er nicht mehr verwendet wird.

Die Verwendung von .family und .autoDispose behebt dieses Speicherleck:

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

Übergabe mehrerer Parameter an eine family

family's haben keine eingebaute Unterstützung für die Übergabe mehrerer Werte an einen Provider.

Andererseits kann dieser Wert beliebig sein (solange er mit den den zuvor genannten Einschränkungen übereinstimmt).

Dazu gehört:

Hier ist ein Beispiel mit Freezed und equatable:

@freezed
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);
// Benutze userId/locale
});

@override
Widget build(BuildContext context, WidgetRef ref) {
int userId; // Lesen Sie die Benutzer-ID von irgendwoher
final locale = Localizations.localeOf(context);

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

...
}