Provider:WatchとRead
CoddyのFlutterジャーニー「状態管理」セクションの一部。レッスン 11/27。
Providerからモデルを取得する方法は2つあり、それぞれ異なる役割を果たします。
context.watch<StepCounter>()はモデルを取得し、同時に購読します。モデルがnotifyListeners()を呼び出すと、このウィジェットは再度ビルドされます。画面に表示するものには、build内で使います。
context.read<StepCounter>()は、購読せずにモデルを一度だけ取得します。メソッドを呼び出したいだけで、何も表示する必要がない場合は、onPressedなどのコールバック内で使います。
Widget build(BuildContext context) {
final steps = context.watch<StepCounter>().steps; // 表示する
return ElevatedButton(
onPressed: () => context.read<StepCounter>().walk(), // 動作する
child: Text('$steps steps'),
);
}使い分けを間違えると、その違いがわかります。build内でreadを使うと、最初の値がずっと表示されます。onPressed内でwatchを使うとエラーになります。タップはビルドではなく、購読するものがないためです。
チャレンジ
簡単Walkはモデルに1000歩を加算しますが、画面は0 stepsのままです。
- 歩数の行がモデルに追従するようにして、タップするたびに新しい数値が表示されるようにします。
- ボタンの呼び出しはそのままにします。
自分で試してみよう
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class StepCounter extends ChangeNotifier {
int _steps = 0;
int get steps => _steps;
void walk() {
_steps += 1000;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => StepCounter(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final steps = context.read<StepCounter>().steps;
return Scaffold(
appBar: AppBar(title: const Text('Steps')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('$steps steps', style: const TextStyle(fontSize: 40)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
context.read<StepCounter>().walk();
},
child: const Text('Walk'),
),
],
),
),
);
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
状態管理のすべてのレッスン
3Provider
Provider:Modelを共有するnotifyListenersを呼び出すProvider:WatchとReadProvider:Consumer2つの画面、1つのModelModel内のオブジェクトのリスト複数のModel:MultiProvider自分で練習してみよう: Flutterオンラインコンパイラ