Menu
CoddyTech

Proveedores que observan otros proveedores

Parte de la sección Gestión del estado del Journey de Flutter de Coddy. Lección 20 de 27.

Parte del estado se deriva de otro estado: el total de minutos es la suma de los entrenamientos. Podrías sumarlos en cada widget que muestre un total, o escribirlo una sola vez, como un proveedor que observa a otro proveedor:

final totalMinutesProvider = Provider((ref) {
  final workouts = ref.watch(workoutsProvider);
  return workouts.fold(0, (sum, w) => sum + w.minutes);
});

La función de un proveedor también recibe un ref. Al usar ref.watch dentro de ella, Riverpod recuerda que el total depende de los entrenamientos. Añade un entrenamiento y se vuelve a calcular el total, y todos los widgets que observan el total se vuelven a construir.

Usa ref.watch aquí, no ref.read. read toma la lista una sola vez, cuando se calcula el total por primera vez, y el total nunca cambia después de eso.

Esta es la idea del getter que vimos antes, aplicada a toda la aplicación: guarda lo menos posible y calcula el resto a partir de ello.

challenge icon

Desafío

Intermedio

La barra superior observa totalMinutesProvider, pero ese proveedor siempre devuelve 0.

  • Haz que observe workoutsProvider y devuelva la suma de los minutes de cada entrenamiento.

Pruébalo tú mismo

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 iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Gestión del estado

Practica por tu cuenta: Compilador de Flutter online