Provider, die andere Provider beobachten
Teil des Abschnitts State Management der Flutter-Journey von Coddy. Lektion 20 von 27.
Einige Zustände ergeben sich aus anderen Zuständen: Die Gesamtminuten sind die Summe der Trainingseinheiten. Du könntest sie in jedem Widget addieren, das eine Gesamtsumme anzeigt, oder die Berechnung einmal schreiben – als Provider, der einen anderen Provider beobachtet:
final totalMinutesProvider = Provider((ref) {
final workouts = ref.watch(workoutsProvider);
return workouts.fold(0, (sum, w) => sum + w.minutes);
});Die Funktion eines Providers erhält ebenfalls ein ref. Wenn du darin ref.watch verwendest, merkt sich Riverpod, dass die Gesamtminuten von den Trainingseinheiten abhängen. Fügst du eine Trainingseinheit hinzu, werden die Gesamtminuten erneut berechnet, und jedes Widget, das sie beobachtet, wird neu aufgebaut.
Verwende hier ref.watch, nicht ref.read. Mit read wird die Liste einmal abgerufen, wenn die Gesamtminuten zum ersten Mal berechnet werden, und danach ändern sie sich nie wieder.
Das ist die Getter-Idee von vorhin, übertragen auf die ganze App: Speichere so wenig wie möglich und berechne den Rest daraus.
Aufgabe
MittelDie obere Leiste beobachtet totalMinutesProvider, aber dieser Provider gibt immer 0 zurück.
- Lass sie
workoutsProviderbeobachten und die Summe derminutesaller Workouts zurückgeben.
Probier es selbst
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class Workout {
Workout(this.name, this.minutes);
final String name;
final int minutes;
}
class WorkoutLog extends Notifier<List<Workout>> {
@override
List<Workout> build() => [];
void add(Workout workout) {
state = [...state, workout];
}
}
final workoutsProvider = NotifierProvider<WorkoutLog, List<Workout>>(WorkoutLog.new);
final totalMinutesProvider = Provider((ref) {
return 0;
});
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: LogPage(),
);
}
}
class LogPage extends ConsumerWidget {
const LogPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final workouts = ref.watch(workoutsProvider);
final total = ref.watch(totalMinutesProvider);
return Scaffold(
appBar: AppBar(title: Text('Total: $total min')),
body: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => ref.read(workoutsProvider.notifier).add(Workout('Run', 30)),
child: const Text('Run'),
),
const SizedBox(width: 16),
ElevatedButton(
onPressed: () => ref.read(workoutsProvider.notifier).add(Workout('Yoga', 20)),
child: const Text('Yoga'),
),
],
),
Expanded(
child: ListView(
children: [
for (final w in workouts) ListTile(title: Text(w.name), trailing: Text('${w.minutes} min')),
],
),
),
],
),
);
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in State Management
1State nach oben weitergeben
State an ein Kind weitergebenEinen Callback an ein Kind weitergebenCallbacks, die einen Wert übergebenState nach oben verschieben4Riverpod
Riverpod: ProviderScopeConsumerWidget und ref.watchRiverpod: StateProviderRiverpod: NotifierProvider, die andere Provider beobachtenDen Speicherort des Zustands wählenÜbe selbstständig: Online-Flutter-Compiler