
STEP3で静的な業務画面モックを作ったことで、「FlutterでUIを組む感覚」はかなり掴めてきたと思います。
ここから先、Flutterを業務アプリとして成立させるために、避けて通れないのが「状態管理」です。
でも、この段階でProvider や Riverpod に飛びつく必要はありません。
まずは setStateで何ができて、何ができないのか を、きちんと体感することが重要です。
ということで、今回は「状態管理」の基礎をやります。
setStateの限界を理解する
setStateは、Flutterにおける最も基本的な状態更新手段です。
StatefulWidgetの中で状態を変更し、UIを再描画させる。それだけの仕組み。
小さな画面や、単純なフォームであれば、setStateはとても分かりやすく、強力です。
ただし、少しでも画面が複雑になると、次のような違和感が出てきます。
・状態とUIが密結合になる
・どの変更が、どのUIに影響するのか追いづらい
・ロジックがWidgetの中に溜まり始める
この「違和感」を感じ取れるようになること自体が、このSTEPの重要なゴールです。
状態の持ち方と責務分離の考え方
Flutter初心者がやりがちなのは、「全部Widgetの中に書いてしまう」ことです。
最初はそれで問題ありません。
むしろ、無理に分離しない方が理解は早いです。
ただし、意識しておきたいのは、「UI」と「状態」は役割が違うという点です。
・UIは、状態をどう表示するか
・状態は、何がどう変わるか
この2つを頭の中で分けて考えるだけで、コードの見通しはかなり良くなります。
このSTEPでは、
状態はWidgetのStateに閉じ込めるというルールだけ守れば十分です。
小規模画面における設計パターン
業務アプリでよくある小規模画面、たとえば検索フォームや入力フォーム。
こうした画面では、「1画面 = 1つのStatefulWidget」という構成が非常に相性が良いです。
画面全体の状態をそのWidgetが持ち、ユーザー操作に応じてsetStateで更新する。
複雑な抽象化をしなくても、十分に読みやすく、壊れにくい構造になります。
この段階では、拡張性よりも分かりやすさを優先するのが正解です。
成果物:入力 → 画面反映のフォーム
ここで、STEP4の成果物として、「入力した内容が即座に画面に反映される」シンプルなフォームを作ってみます。
ロジックは最小限、setStateの役割がはっきり分かる例です。
サンプルコード
lib/main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: SearchFormPage(),
debugShowCheckedModeBanner: false,
);
}
}
class SearchFormPage extends StatefulWidget {
const SearchFormPage({super.key});
@override
State<SearchFormPage> createState() => _SearchFormPageState();
}
class _SearchFormPageState extends State<SearchFormPage> {
String _inputName = '';
String _displayName = '未検索';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('顧客検索'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'顧客名',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: TextField(
onChanged: (value) {
setState(() {
_inputName = value;
});
},
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: '顧客名を入力してください',
),
),
),
const SizedBox(width: 12),
ElevatedButton(
onPressed: () {
setState(() {
_displayName =
_inputName.isEmpty ? '未検索' : _inputName;
});
},
child: const Text('検索'),
),
],
),
const SizedBox(height: 24),
const Text(
'検索結果(ダミー)',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
_displayName,
style: const TextStyle(fontSize: 18),
),
],
),
),
);
}
}
このコードのポイント
このフォームで重要なのは、「setStateがどこで呼ばれているか」です。
入力が変わった瞬間に状態を更新し、その結果が即座にUIへ反映される。
Flutterでは、状態が変わる → UIが再構築される という流れが、非常に素直に書けます。
この感覚を一度掴めると、状態管理が「難しいもの」ではなく、「制御できるもの」に変わります。
このSTEPのまとめ
このSTEPでは、高度な状態管理は一切扱っていません。
それで問題ありません。
・setStateで何ができるか
・どこから辛くなりそうか
・状態とUIを分けて考える感覚
この3点が分かれば、このSTEPは成功です。
あとがき
0 件のコメント:
コメントを投稿