「どっちを使えばいいの?」と混乱しがちな2つのメソッド。
今回はこの違いを 完全に 理解します。
目次
結論を先に言います
context.watch → 「監視する」変化があれば画面を更新する
context.read → 「一回だけ読む(実行する)」更新はしない
これだけです。でも「どっちをいつ使うか」が最初はわかりにくいので、具体例で見ていきます。
テレビに例えて考える
context.watch → テレビを「つけっぱなし」にしている状態
何か変わればすぐ画面が変わる
context.read → テレビを「一瞬だけチラ見」する状態
確認したらもう見ない
context.watch を使う場面
「データの表示」に使います。
データが変わったら画面も変わってほしい場所です。
class StudentListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// watch → 生徒リストを「監視」している
// 生徒が追加・削除されるたびに自動で画面が更新される
final vm = context.watch<StudentViewModel>();
return ListView.builder(
itemCount: vm.students.length, // ← データが変わると自動更新
itemBuilder: (_, index) => ListTile(
title: Text(vm.students[index].name),
),
);
}
}
context.read を使う場面
「ボタンを押したときの処理」に使います。
「データを表示する必要はなく、メソッドを実行するだけ」の場所です。
FloatingActionButton(
onPressed: () {
// read → 「addStudentを実行するだけ」で監視はしない
context.read<StudentViewModel>().addStudent('花子さん', 5000);
},
child: Icon(Icons.add),
),
なぜボタンに watch を使ってはいけないの?
// ❌ NG:ボタンに watch を使った場合
FloatingActionButton(
onPressed: () {
// watch を使うと、StudentViewModel が変わるたびに
// このボタンも再描画される → 無駄な処理が増える!
context.watch<StudentViewModel>().addStudent('花子さん', 5000);
},
child: Icon(Icons.add),
),
context.watch は build メソッドの中で使う のが基本です。
ボタンの onPressed の中で使うと無駄な再描画が起きます。
図で整理する
┌──────────────────────────────────────┐
│ build() の中 → context.watch を使う │
│ │
│ Text(vm.students.length.toString())│ ← データ表示
│ ListView(vm.students) │ ← リスト表示
│ │
│ ボタンの処理 → context.read を使う │
│ │
│ onPressed: () { │
│ context.read<VM>().addStudent() │ ← メソッド実行
│ } │
└──────────────────────────────────────┘
まとめて書いたコードで確認
class StudentListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// ✅ watch:表示に使う(監視する)
final vm = context.watch<StudentViewModel>();
return Scaffold(
appBar: AppBar(
title: Text('生徒一覧(${vm.students.length}人)'), // 自動更新される
),
body: ListView.builder(
itemCount: vm.students.length,
itemBuilder: (_, index) => ListTile(
title: Text(vm.students[index].name),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
// ✅ read:ボタン処理に使う(監視しない)
context.read<StudentViewModel>().removeStudent(index);
},
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// ✅ read:ボタン処理に使う(監視しない)
context.read<StudentViewModel>().addStudent('新しい生徒', 5000);
},
child: Icon(Icons.add),
),
);
}
}
もう一つ:context.select という便利なやつ
context.watch は ViewModel 全体を監視します。
ViewModel の一部だけを監視したいときは context.select が使えます。
// watch → StudentViewModel 全体を監視(何か変われば再描画)
final vm = context.watch<StudentViewModel>();
// select → 生徒の人数だけを監視(人数が変わったときだけ再描画)
final count = context.select<StudentViewModel, int>(
(vm) => vm.students.length,
);
生徒数が変わったときだけ更新したい AppBar などに使うと効率的です。
ただし最初は watch と read だけ覚えれば十分です!
判断フローチャート
画面にデータを表示したい?
↓ YES
context.watch を使う ✅
ボタンを押したときにメソッドを実行したい?
↓ YES
context.read を使う ✅
どちらか迷ったら?
↓
「表示に関係している → watch」
「実行するだけ → read」と考える
今回のまとめ
| context.watch | context.read | |
|---|---|---|
| 使う場所 | build() の中(表示) | onPressed など(処理) |
| 監視するか | する(変化で再描画) | しない |
| 覚え方 | 見続ける(テレビをつけっぱなし) | チラ見(一瞬だけ確認) |
次回予告
最終回は MultiProvider と MVVM設計 を組み合わせて、アプリ全体の構造を整理する方法を解説します。
// こういう構造がスッキリ理解できるようになります!
List<SingleChildWidget> globalProviders = [
...independentModels,
...dependentModels,
...viewModels,
];
シリーズ全体の「まとめ回」です!
このシリーズの全体構成
- 第1回:Providerって何?なぜ必要なの?
- 第2回:ChangeNotifier と notifyListeners() を理解する
- 第3回(今回):context.watch と context.read の違い
- 第4回:MultiProvider と MVVM設計でアプリを整理する
Flutter / Provider / context.watch / context.read / 初心者 / アプリ開発
