
Stateful Widget パターンは、特に Flutter(Dart)のUI設計思想から広まった概念ですが、
他のフロントエンド(React、Vue、Svelteなど)にも通じる状態をもつUIコンポーネント設計の基本パターンです。
Stateful Widget Patternとは
UI(見た目)と状態(データ)を一体化させて管理すると言うのが特徴の設計パターンです。
コンポーネント(Widget)が、
自分自身の状態を保持し、それに応じて再描画(再レンダリング)する。
外部の状態管理を使わず、内部で完結するUI動作を実現できます。
構造イメージ
StatefulWidget
├─ build() → UIツリーを定義
└─ createState() → 状態クラスを生成
State (内部状態)
└─ setState() → 状態更新でUI再構築
| 概念 |
意味 |
| StatefulWidget |
状態をもつUI部品 |
| State |
UIの内部状態(変更可能) |
| setState() |
状態を変更しUIを再描画 |
| StatelessWidget |
状態を持たない固定UI |
サンプルコード1 : Flutterでの例(Dart)
import 'package:flutter/material.dart';
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int count = 0;
void increment() {
setState(() { // 状態変更をUIに通知
count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: $count', style: TextStyle(fontSize: 24)),
ElevatedButton(
onPressed: increment,
child: Text('Increment'),
),
],
);
}
}
解説
・StatefulWidget:UI構造を持つクラス。
・_CounterWidgetState:状態を管理するクラス。
・setState():状態が変わったことを通知 → Flutterが自動的に再描画。
サンプルコード2 : JavaScriptでの近似例(React)
function Counter() {
const [count, setCount] = React.useState(0);
return (
<div style={{ textAlign: 'center' }}>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
解説
・ReactのuseStateは、Stateful WidgetのsetState()とほぼ同じ役割。
・Counterコンポーネント自身が「状態 + UI」を内包している。
サンプルコード3 : Javascript(Vanilla)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Vanilla Stateful Widget Pattern Demo</title>
<style>
body {
font-family: sans-serif;
text-align: center;
padding: 40px;
}
button {
font-size: 16px;
padding: 10px 20px;
margin-top: 20px;
}
.counter {
font-size: 32px;
margin-top: 10px;
}
</style>
</head>
<body>
<div id="app"></div>
<script>
// Stateful Widget のようなコンポーネントクラス
class CounterWidget {
constructor(root) {
this.root = root;
this.state = { count: 0 };
this.render();
}
// 状態を更新して再描画
setState(newState) {
this.state = { ...this.state, ...newState };
this.render();
}
// コンポーネントの描画
render() {
this.root.innerHTML = `
<h2>Stateful Widget Pattern (Vanilla JS)</h2>
<div class="counter">${this.state.count}</div>
<button id="inc">+ Increment</button>
<button id="dec">- Decrement</button>
`;
// イベントハンドラを再登録
this.root.querySelector("#inc").onclick = () =>
this.setState({ count: this.state.count + 1 });
this.root.querySelector("#dec").onclick = () =>
this.setState({ count: this.state.count - 1 });
}
}
// 起動
const app = document.getElementById("app");
new CounterWidget(app);
</script>
</body>
</html>
解説
・CounterWidget クラスが「Stateful Widget」に相当
・this.state がコンポーネント固有の状態を保持
・setState() メソッドで状態変更 → render() 再呼び出し
・DOM操作をラップしてReactのような再レンダリング体験を再現
メリット
・各ウィジェットが自律的に動作し、外部依存が少ない。
・小規模UIでの状態管理が簡単。
・再利用しやすく、デバッグも容易。
デメリット
・大規模アプリになると、状態が分散して管理が複雑化。
・複数Widget間で状態共有が必要な場合、Statefulだけでは破綻する。
→ → Flux / Redux / Riverpod / Bloc などの状態管理へ発展。
あとがき
FlutterやReactのフレームワークは、この Stateful Widgetパターン そのものと言ってもいいシステムです。
HTMLのDIM構造をブロックとして保持して、それをオブジェクトとして使うことができると言う、フロントエンド特有のパターンですね。
個人的には、Vanilla JS(素書きのJS)でも、外部に設置したHTMLファイルをテキストでAjax読み込みをして、それをデータベースなどから取得したデータのオブジェクトで一括変換する処理は実施していましたが、そこからのイベント発火ができるそれぞれのフレームワークは非常によくできていると改めて感じました。
Vanilla JSにこだわっているのは個人的な理由なので、通常はFlatterやReactなどを使う際に、このデザインパターンを意識してみると、柔軟な設計につながると思いますよ。
0 件のコメント:
コメントを投稿