他のProviderを監視するProvider
CoddyのFlutterジャーニー「状態管理」セクションの一部。レッスン 20/27。
一部の状態は、別の状態から導き出せます。合計分数は、ワークアウトの合計です。合計を表示する各ウィジェットで毎回計算することもできますし、別のプロバイダーを監視するプロバイダーとして、一度だけ書くこともできます。
final totalMinutesProvider = Provider((ref) {
final workouts = ref.watch(workoutsProvider);
return workouts.fold(0, (sum, w) => sum + w.minutes);
});プロバイダーの関数にもrefが渡されます。その中でref.watchを使うと、Riverpodは合計がワークアウトに依存していることを記憶します。ワークアウトを追加すると、合計が再計算され、合計を監視しているすべてのウィジェットが再ビルドされます。
ここではref.readではなく、ref.watchを使います。readは、合計が最初に計算されるときにリストを一度だけ取得するため、その後、合計は変わりません。
これは先ほどのゲッターの考え方をアプリ全体に当てはめたものです。保存する状態はできるだけ少なくし、残りはそこから計算しましょう。
チャレンジ
中級上部バーはtotalMinutesProviderを監視しますが、このプロバイダーは常に0を返します。
workoutsProviderを監視し、すべてのワークアウトのminutesの合計を返すようにしてください。
自分で試してみよう
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')),
],
),
),
],
),
);
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
状態管理のすべてのレッスン
4Riverpod
Riverpod: ProviderScopeConsumerWidgetとref.watchRiverpod: StateProviderRiverpod: Notifier他のProviderを監視するProvider状態の置き場所を選ぶ自分で練習してみよう: Flutterオンラインコンパイラ