This page is available in Japanese only.

第 3 回では、決まったメモを一覧に並べました。第 4 回は、メモを追加したり、チェックを付けたりできるようにします。
そのために必要なのが「状態(State)」の考え方です。Flutter では、状態が変わったら、画面(ウィジェット)を作り直して描き直す、という仕組みで画面を更新します。

状態には 2 種類ある
種類 | 例 | 管理の方法 |
|---|---|---|
画面の中だけで使う状態 | 入力中の文字、開いているタブ、アニメーションの途中 |
|
アプリ全体で使う状態 | メモの一覧、ログインしているユーザー、カートの中身 |
|
Flutter の公式ドキュメントでも、setState は「ウィジェットの中だけの一時的な状態」向けの低レベルな方法と説明されています。まずは setState から見ていきましょう。

setState: 画面の中だけで使う状態
class CounterMemoPage extends StatefulWidget {
const CounterMemoPage({super.key});
@override
State<CounterMemoPage> createState() => _CounterMemoPageState();
}
class _CounterMemoPageState extends State<CounterMemoPage> {
final _memos = <String>[];
void _add() {
setState(() {
_memos.add('メモ ${_memos.length + 1}');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('メモ(${_memos.length} 件)')),
body: ListView(
children: [for (final m in _memos) ListTile(title: Text(m))],
),
floatingActionButton: FloatingActionButton(
onPressed: _add,
child: const Icon(Icons.add),
),
);
}
}StatefulWidgetは、ウィジェット本体と、状態を持つStateクラスの 2 つで 1 組です- 値を変えるときは `setState(() { ... })` の中で変えます。こうすると Flutter が
buildを呼び直し、画面が更新されます setStateを使わずに_memos.add(...)だけ書くと、データは変わっても画面は変わりません(よくある間違いです)
この書き方は簡単ですが、メモの一覧を別の画面からも使いたい、保存もしたいとなると、画面のクラスの中に処理が増えていきます。そこで、データを画面の外に出します。
ChangeNotifier: アプリ全体のデータを画面の外に置く
ChangeNotifier は、Flutter に最初から入っている「変わったら知らせる」ための仕組みです。メモの一覧と、それを変える処理を 1 つのクラス(ストア)にまとめます。
class MemoStore extends ChangeNotifier {
MemoStore(this._repository);
final MemoRepository _repository;
List<Memo> _memos = [];
int _nextId = 1;
List<Memo> get memos => List.unmodifiable(_memos);
int get remaining => _memos.where((m) => !m.done).length;
void add(String text) {
if (text.trim().isEmpty) return;
_memos = [..._memos, Memo(id: _nextId++, text: text.trim())];
_changed();
}
void toggle(int id) {
_memos = [
for (final m in _memos) m.id == id ? m.copyWith(done: !m.done) : m,
];
_changed();
}
void remove(int id) {
_memos = _memos.where((m) => m.id != id).toList();
_changed();
}
void _changed() {
notifyListeners(); // 画面を描き直す
_repository.save(_memos); // 保存は裏で
}
}ポイントは 3 つです。
- データは外から直接変えさせない:
memosは変更できないリスト(List.unmodifiable)で渡し、変更はadd・toggle・removeを通してだけ行います - 変えたら `notifyListeners()`: これで、このストアを見ている画面に「変わった」と知らせます
- 新しいリストを作って入れ替える: 第 2 回の
copyWithのように、元のデータを書き換えずに新しいものを作ると、変更の流れを追いやすくなります
ListenableBuilder: 変わったら画面を作り直す
画面の側では、ListenableBuilder でストアを見張ります。notifyListeners() が呼ばれるたびに、builder の中が作り直されます。
return ListenableBuilder(
listenable: store,
builder: (context, _) {
final memos = store.memos;
return Scaffold(
appBar: AppBar(title: Text('メモ(残り ${store.remaining} 件)')),
body: ListView.separated(
itemCount: memos.length,
separatorBuilder: (_, _) => const Divider(height: 1),
itemBuilder: (context, index) {
final memo = memos[index];
return Dismissible(
key: ValueKey(memo.id),
onDismissed: (_) => store.remove(memo.id), // 横にスワイプで削除
background: Container(color: Colors.red.shade100),
child: CheckboxListTile(
value: memo.done,
onChanged: (_) => store.toggle(memo.id), // チェックの ON/OFF
title: Text(memo.text),
),
);
},
),
);
},
);CheckboxListTileをタップするとstore.toggleが呼ばれ、ストアがnotifyListeners()で知らせ、ListenableBuilderが画面を作り直しますDismissibleは、横にスワイプして消せるようにするウィジェットです。keyには、メモごとに変わらない値(ここでは id)を指定します(_, _)の_は「使わない引数」です。Dart 3.7 からは、使わない引数を何個でも_と書けます
画面のクラスは「表示と、ボタンが押されたらストアを呼ぶ」だけになり、データの扱いはストアに集まります。
Riverpod や provider は使わないの?
Flutter の状態管理には、provider・Riverpod・Bloc など、多くのパッケージがあります。公式ドキュメントでも、アプリの複雑さやチームの好みに応じて、こうしたパッケージを使うと便利な場合があると紹介されています。
この講座では、仕組みを理解するために、Flutter の標準の `ChangeNotifier` と `ListenableBuilder` だけで作っています。実はこれらのパッケージも、内部では同じような「変わったら知らせる」仕組みを使っています。まずはこの形を理解してから、規模が大きくなったときにパッケージを検討するのがおすすめです。

まとめ
- Flutter は、状態が変わったら画面を作り直すことで表示を更新します
- 画面の中だけの状態は `StatefulWidget` と `setState`。値は必ず
setStateの中で変えます - アプリ全体のデータは `ChangeNotifier` にまとめ、変えたら `notifyListeners()`
- 画面は `ListenableBuilder` でストアを見張り、変わったら作り直します
- 大きなアプリでは provider・Riverpod なども選択肢ですが、まずは標準の仕組みで考え方を身につけましょう
次回(第 5 回)は、API からデータを取ってきて、メモを端末に保存します。
Flutter 入門講座(全 6 回)
- Flutter とは?できることと開発環境の作り方
- Dart の基本文法
- ウィジェットで画面を作る
- 状態管理の第一歩(この記事・11月12日)
- API からデータを取得し、端末に保存する(11月13日公開予定)
- 画面遷移・テスト・リリースまで(11月14日公開予定)
アプリの企画段階からのご相談も承ります。フォームは 24 時間受付です
※ Flutter は Google LLC の商標です。
参考
- Flutter 公式ドキュメント「List of state management approaches」
- Flutter 公式ドキュメント「Adding interactivity to your Flutter app」
Contact
Let's talk about your project.
Web, system and app development, video and more. Get in touch with us here.

