Menu
CoddyTech

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.

challenge icon

Défi

Moyen

La barre supérieure observe totalMinutesProvider, mais ce fournisseur renvoie toujours 0.

  • Fais-lui observer workoutsProvider et renvoyer la somme des minutes de 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')),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur Flutter en ligne