今後モバイルアプリ開発に関わる可能性があるため、代表的なウィジェットの特徴を簡潔にまとめてみました。
ウィジェット | 状態管理 | 動的UI更新 | シンプルさ | パフォーマンス | Providerの使用 |
---|---|---|---|---|---|
StatelessWidget | × | × | 〇 | 〇 | × |
StatefulWidget | 〇 | 〇 | × | △ | × |
ConsumerWidget | 〇 | 〇 | △ | 〇 | 〇 |
StatefulConsumerWidget | 〇 | 〇 | × | △ | 〇 |
1. StatelessWidget
状態を持たないウィジェット。ウィジェットの状態が変わらない場合に使用される。
静的なUI要素や、状態が外部から提供される場合に適している。
メリット
・シンプルで軽量
・状態管理が不要なため、コードが簡潔
・パフォーマンス〇
デメリット
・状態を持たないため、動的なUIの更新ができない
import 'package:flutter/material.dart';
class MyStatelessWidget extends StatelessWidget {
final String title;
MyStatelessWidget({required this.title});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text('This is a StatelessWidget'),
),
);
}
}
2. StatefulWidget
内部に状態を持つウィジェット。状態が変化する場合に使用される。
動的に変化するUIに適している。
メリット:
・動的なUIの更新が可能
・状態管理がウィジェット内で完結する
デメリット:
・コードが複雑になる可能性がある
・パフォーマンス△
import 'package:flutter/material.dart';
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('StatefulWidget Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
3. ConsumerWidget
ConsumerWidgetは、Providerを使用して状態管理を行うウィジェット。
Providerから状態を取得し、UIを更新することができる。
メリット:
・Providerを使用することで、状態管理が容易
・状態の変更に応じて、必要な部分のみを再ビルドできる
デメリット:
・Providerの理解が必要
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final counterProvider = StateProvider<int>((ref) => 0);
class MyConsumerWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(
title: Text('ConsumerWidget Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
'$counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
4. StatefulConsumerWidget
StatefulWidgetとConsumerWidgetの機能を組み合わせたウィジェット。
内部に状態を持ちながら、Providerからの状態も利用できる。
メリット
・内部状態と外部状態の両方を管理できる
・柔軟な状態管理が可能
デメリット:
・複雑な状態管理が必要なため、コードが複雑になる可能性がある
・Providerの理解とセットアップが必要
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final counterProvider = StateProvider<int>((ref) => 0);
class MyStatefulConsumerWidget extends StatefulWidget {
@override
_MyStatefulConsumerWidgetState createState() => _MyStatefulConsumerWidgetState();
}
class _MyStatefulConsumerWidgetState extends State<MyStatefulConsumerWidget> {
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, ref, child) {
final counter = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(
title: Text('StatefulConsumerWidget Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
'$counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
},
);
}
}
まとめ
パフォーマンスを考えると、UI部分をStatelessWidgetで作成してデータ更新などで再描画が必要な部分のみConsumerWidgetを使用するのが一番よさそう
参考:
StatefulWidget & StatelessWidget
ConsumerWidget
StatefulConsumerWidget