Les providers qui observent d’autres providers
Fait partie de la section Gestion d’état du Journey Flutter de Coddy. Leçon 20 sur 27.
Une partie de l’état découle d’un autre état : le nombre total de minutes correspond à la somme des séances d’entraînement. Tu pourrais les additionner dans chaque widget qui affiche un total, ou le faire une seule fois en écrivant un fournisseur qui observe un autre fournisseur :
final totalMinutesProvider = Provider((ref) {
final workouts = ref.watch(workoutsProvider);
return workouts.fold(0, (sum, w) => sum + w.minutes);
});La fonction d’un fournisseur reçoit aussi une ref. Avec ref.watch à l’intérieur, Riverpod se souvient que le total dépend des séances d’entraînement. Ajoute une séance d’entraînement : le total est recalculé et chaque widget qui observe le total est reconstruit.
Utilise ref.watch ici, pas ref.read. read récupère la liste une seule fois, au premier calcul du total, et celui-ci ne change plus ensuite.
C’est le principe du getter vu plus tôt, appliqué à toute l’application : stocke le moins de données possible et calcule le reste à partir de celles-ci.
Défi
MoyenLa barre supérieure observe totalMinutesProvider, mais ce fournisseur renvoie toujours 0.
- Fais-lui observer
workoutsProvideret renvoyer la somme desminutesde chaque entraînement.
Essayez vous-même
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')),
],
),
),
],
),
);
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Gestion d’état
1Remonter l’état
Transmettre l’état à un composant enfantTransmettre une fonction de rappel à un composant enfantFonctions de rappel qui transmettent une valeurRemonter l’état4Riverpod
Riverpod : ProviderScopeConsumerWidget et ref.watchRiverpod : StateProviderRiverpod : NotifierLes providers qui observent d’autres providersChoisir où réside l’étatEntraînez-vous par vous-même : Compilateur Flutter en ligne