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.
Desafío
IntermedioLa barra superior observa totalMinutesProvider, pero ese proveedor siempre devuelve 0.
- Haz que observe
workoutsProvidery devuelva la suma de losminutesde 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')),
],
),
),
],
),
);
}
}
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
1Elevar el estado
Pasar el estado a un componente hijoPasar una función callback a un componente hijoCallbacks que envían un valorElevar el estado4Riverpod
Riverpod: ProviderScopeConsumerWidget y ref.watchRiverpod: StateProviderRiverpod: NotifierProveedores que observan otros proveedoresElegir dónde vive el estadoPractica por tu cuenta: Compilador de Flutter online