Providers que observam Providers
Parte da seção Gerenciamento de estado do Journey de Flutter da Coddy. Lição 20 de 27.
Alguns estados derivam de outros: o total de minutos é a soma dos treinos. Você poderia somá-los em cada widget que mostra um total ou escrever isso uma única vez, como um provider que observa outro provider:
final totalMinutesProvider = Provider((ref) {
final workouts = ref.watch(workoutsProvider);
return workouts.fold(0, (sum, w) => sum + w.minutes);
});A função de um provider também recebe um ref. Com ref.watch dentro dela, o Riverpod se lembra de que o total depende dos treinos. Adicione um treino, e o total será calculado novamente, e todos os widgets que observam o total serão reconstruídos.
Use ref.watch aqui, não ref.read. read obtém a lista uma única vez, quando o total é calculado pela primeira vez, e o total nunca muda depois disso.
Essa é a ideia de getter de antes, aplicada ao app inteiro: armazene o mínimo possível e calcule o restante a partir disso.
Desafio
MédioA barra superior observa totalMinutesProvider, mas esse provedor sempre retorna 0.
- Faça com que ela observe
workoutsProvidere retorne a soma dosminutesde cada treino.
Experimente você mesmo
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 lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Gerenciamento de estado
1Elevando o estado
Passar o estado para um componente filhoPassar um callback para um componente filhoCallbacks que enviam um valorElevar o estado4Riverpod
Riverpod: ProviderScopeConsumerWidget e ref.watchRiverpod: StateProviderRiverpod: NotifierProviders que observam ProvidersEscolhendo onde o estado ficaPratique por conta própria: Compilador de Flutter online