Flutter Riverpod 3.0 Architektur-Leitfaden: Notifier, AsyncNotifier und AutoDispose Muster

Flutter Riverpod 3.0 Architektur-Leitfaden: Notifier, AsyncNotifier und AutoDispose Muster
Riverpod, Flutter’s führende State-Management-Bibliothek, bringt mit der Version 3.0 eine grundlegende Überarbeitung der Architektur. Bisherige Muster wie StateNotifier, ChangeNotifier und manuell erstellte Provider werden durch klassenbasierte Notifier / AsyncNotifier und standardisierte Code-Generierung mittels riverpod_generator ersetzt.
Zur Einordnung: Die Codegenerierung mit @riverpod arbeitet bereits seit Riverpod 2.0 standardmäßig mit autoDispose und gibt den Speicher beim Verlassen von Ansichten automatisch frei. Was sich in 3.0 tatsächlich ändert, ist die Vereinheitlichung der zuvor auf AutoDispose*/Family* verteilten Provider-Typinterfaces zu einem einzigen Provider/Notifier-API, was die Nutzung deutlich vereinfacht.
In diesem Artikel behandeln wir die zentralen Änderungen in Riverpod 3.0 sowie praxiserprobte Produktionsmuster für Notifier, AsyncNotifier und family-Parameter.
1. Vergleich: Legacy Riverpod vs. Riverpod 3.0 Standards
| Merkmal | Legacy Riverpod (1.x / 2.x) | Riverpod 3.0 Standard |
|---|---|---|
| Typinterface | Aufgeteilt in Provider / AutoDisposeProvider / FamilyProvider usw. |
Vereinheitlicht zu Provider/Notifier (Standardmäßiges autoDispose gilt bei der @riverpod-Codegenerierung unverändert bereits seit 2.0) |
| State Controller | StateNotifierProvider / FutureProvider |
Notifier / AsyncNotifier mit @riverpod-Annotation |
| Family-Argumente | Manuelle .family-Wrapper |
Native Methodenparameter in der generierten build-Methode |
| Asynchrones Handling | Manuelles AsyncValue.when() Handling |
Erweiterte AsyncValue-Helper & automatischer Guard-Schutz |
2. Praktische Notifier und AsyncNotifier Implementierung
1) Synchroner Status: Notifier Implementierung
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'counter_provider.g.dart';
// @riverpod Annotation aktiviert autoDispose standardmäßig
@riverpod
class CounterNotifier extends _$CounterNotifier {
@override
int build() {
// Initialer Status (wird beim erneut Anzeigen neu ausgewertet)
return 0;
}
void increment() {
state = state + 1;
}
void decrement() {
state = state - 1;
}
}
2) Asynchroner Status: AsyncNotifier & Family Implementierung
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../models/user.dart';
part 'user_provider.g.dart';
// Family-Parameter werden direkt als Argumente der build-Methode übergeben
@riverpod
class UserDetailNotifier extends _$UserDetailNotifier {
@override
Future<User> build(String userId) async {
// Asynchrones Datenladen
return await ref.read(userRepositoryProvider).fetchUser(userId);
}
Future<void> updateUserName(String newName) async {
// Ladezustand setzen
state = const AsyncLoading();
// Abgesicherte Statusaktualisierung
state = await AsyncValue.guard(() async {
final updatedUser = await ref
.read(userRepositoryProvider)
.updateName(arg, newName); // 'arg' greift auf den Family-Parameter (userId) zu
return updatedUser;
});
}
}
3. AsyncValue Konsum & AutoDispose Handling in Widgets
In der UI-Schicht abonnieren Sie den Status mit ref.watch und verzweigen die Anzeige mittels AsyncValue.when.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class UserProfileScreen extends ConsumerWidget {
final String userId;
const UserProfileScreen({super.key, required this.userId});
@override
Widget build(BuildContext context, WidgetRef ref) {
// Provider mit Family-Parameter abonnieren
final userAsync = ref.watch(userDetailNotifierProvider(userId));
return Scaffold(
appBar: AppBar(title: const Text('Benutzerprofil')),
body: userAsync.when(
data: (user) => Column(
children: [
Text('Name: ${user.name}'),
ElevatedButton(
onPressed: () {
ref
.read(userDetailNotifierProvider(userId).notifier)
.updateUserName('Neuer Name');
},
child: const Text('Name ändern'),
),
],
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, stack) => Center(child: Text('Fehler: $err')),
),
);
}
}
4. Praxistipps zu AutoDispose
- Globale Statuszustände: Für anwendungsweite Provider (wie Login-Tokens oder Themes) setzen Sie explizit
@Riverpod(keepAlive: true). ref.keepAlive()Links nutzen: Um Statuszustände während laufender asynchroner Operationen vorübergehend vor dem Löschen zu schützen, nutzen Siefinal link = ref.keepAlive();und schließen diesen mitlink.close().- Speicherbereinigung: AutoDispose löscht den Status nicht sofort, sobald kein aktiver Consumer mehr im Widget-Baum vorhanden ist, sondern wartet eine Kulanzfrist von einem Frame ab und verwirft den Status nur, wenn er danach weiterhin ungenutzt bleibt. Das sollten Sie bei Caching-Strategien, etwa für zwischengespeicherte Formulareingaben, berücksichtigen.
Zusammenfassung und Fazit
Riverpod 3.0 bringt ein modernes State-Management mit minimalem Boilerplate-Code und integrierter Speichersicherheit.
[!NOTE]
- Nutzen Sie klassenbasierte
NotifierundAsyncNotifieranstelle alterStateNotifier-Muster.- Setzen Sie auf
riverpod_generator, um Family-Parameter und Provider-Definitionen zu automatisieren.- Nutzen Sie die standardmäßige
autoDispose-Regel und kennzeichnen Sie globale Statuszustände explizit mit@Riverpod(keepAlive: true).
Die Verwendung von Riverpod 3.0 verbessert die Typsicherheit und Wartbarkeit Ihrer Flutter-Anwendungen erheblich.