🐈
【Flutter】StatefulWidget,StatelessWidgetで、riverpodの状態更新が可能な箇所と方法の比較まとめ
はじめに
例えば、下記のように、riverpod で state を定義したとします。
注目は、state を更新するためのメソッドupdateMessage
です。
このupdateMessage
メソッドを StatefulWidget, StatelessWidget 内で実行するケースについて、
メソッドの実行箇所と実行方法を比較・まとめしました。
stateの定義
class MessageState with _$MessageState {
const factory MessageState._({
required String message,
}) = _MessageState;
factory MessageState.create({
required String message,
}) =>
MessageState._(
message: message,
);
}
class MessageStateNotifier extends Notifier<MessageState> {
MessageState build() {
const message = "initial message";
return MessageState.create(message: message);
}
void updateMessage(String newMessage) {
state = state.copyWith(message: newMessage);
}
コード比較画像
実行箇所と実行方法まとめ
実行方法/実行箇所 | ① メソッド内 | ②builder 内 | ③ イベント処理内 |
---|---|---|---|
(A) そのまま実行 | エラー | エラー | O |
(B) Future で実行[1] | O | O | - |
(C) addPostFrameCallback で実行 | O | O | - |
- 可能なら、(A) そのまま実行したい。
- しかし、①, ② の箇所では、(A) だとエラーになるため、(B) or (C) で実行する必要がある。
- (B), (C) どちらが最適かは、まだ深堀りしていない[2]。
サンプルコード全体
サンプルコード全体
main.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'home_page.dart';
void main() {
runApp(const ProviderScope(
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
home_page.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'home_page.dart';
void main() {
runApp(const ProviderScope(
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
message_state.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
part 'message_state.freezed.dart';
// --------------------------------------------------
//
// MessageState
//
// --------------------------------------------------
class MessageState with _$MessageState {
const factory MessageState._({
required String message,
}) = _MessageState;
factory MessageState.create({
required String message,
}) =>
MessageState._(
message: message,
);
}
class MessageStateNotifier extends Notifier<MessageState> {
MessageState build() {
const message = "initial message";
return MessageState.create(message: message);
}
void updateMessage(String newMessage) {
state = state.copyWith(message: newMessage);
}
}
typedef MessageStateNotifierProvider
= NotifierProvider<MessageStateNotifier, MessageState>;
MessageStateNotifierProvider messageStateNotifierProviderCreator() {
return NotifierProvider<MessageStateNotifier, MessageState>(
() => MessageStateNotifier());
}
message_stateful_widget.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'message_state.dart';
// --------------------------------------------------
//
// State
//
// --------------------------------------------------
class MessageStatefulWidgetState {
static final messageStateNotiferProvider =
messageStateNotifierProviderCreator();
}
// --------------------------------------------------
//
// Widget
//
// --------------------------------------------------
class MessageStatefulWidget extends StatefulHookConsumerWidget {
const MessageStatefulWidget({super.key, required this.title});
final String title;
ConsumerState<MessageStatefulWidget> createState() =>
_MessageStatefulWidgetState();
}
class _MessageStatefulWidgetState extends ConsumerState<MessageStatefulWidget> {
void initState() {
// unawaited(Future(() {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update initState future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update initState addPostFrameCallback");
// });
super.initState();
}
void didChangeDependencies() {
// unawaited(Future(() {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update didChangeDependencies future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update didChangeDependencies addPostFrameCallback");
// });
super.didChangeDependencies();
}
void didUpdateWidget(covariant MessageStatefulWidget oldWidget) {
// unawaited(Future(() {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update didUpdateWidget future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update didUpdateWidget addPostFrameCallback");
// });
super.didUpdateWidget(oldWidget);
}
void dispose() {
// unawaited(Future(() {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update dispose future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update dispose addPostFrameCallback");
// });
super.dispose();
}
Widget build(BuildContext context) {
// unawaited(Future(() {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update build future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update build addPostFrameCallback");
// });
return LayoutBuilder(builder: (context, constraints) {
// unawaited(Future(() {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update builder future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatefulWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update builder addPostFrameCallback");
// });
return Container(
margin: const EdgeInsets.all(20),
padding: const EdgeInsets.symmetric(horizontal: 20),
width: double.infinity,
color: Colors.grey.withOpacity(0.5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
widget.title,
style: const TextStyle(
fontSize: 24,
),
),
Container(
color: Colors.white,
padding: const EdgeInsets.all(20),
child: Text(
ref
.watch(
MessageStatefulWidgetState.messageStateNotiferProvider)
.message,
),
),
ElevatedButton(
onPressed: () {
ref
.read(MessageStatefulWidgetState
.messageStateNotiferProvider.notifier)
.updateMessage("update onPressed");
},
child: const Text("update message"),
),
],
),
);
});
}
}
message_stateless_widget.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'message_state.dart';
// --------------------------------------------------
//
// State
//
// --------------------------------------------------
class MessageStatelessWidgetState {
static final messageStateNotiferProvider =
messageStateNotifierProviderCreator();
}
// --------------------------------------------------
//
// Widget
//
// --------------------------------------------------
class MessageStatelessWidget extends HookConsumerWidget {
const MessageStatelessWidget({super.key, required this.title});
final String title;
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Widget build(BuildContext context, WidgetRef ref) {
// unawaited(Future(() {
// ref
// .read(MessageStatelessWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update build future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatelessWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update build addPostFrameCallback");
// });
return LayoutBuilder(builder: (context, constraints) {
// unawaited(Future(() {
// ref
// .read(MessageStatelessWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update builder future");
// }));
// WidgetsBinding.instance.addPostFrameCallback((_) {
// ref
// .read(MessageStatelessWidgetState.messageStateNotiferProvider.notifier)
// .updateMessage("update builder addPostFrameCallback");
// });
return Container(
margin: const EdgeInsets.all(20),
padding: const EdgeInsets.symmetric(horizontal: 20),
width: double.infinity,
color: Colors.grey.withOpacity(0.5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
title,
style: const TextStyle(
fontSize: 24,
),
),
Container(
color: Colors.white,
padding: const EdgeInsets.all(20),
child: Text(
ref
.watch(
MessageStatelessWidgetState.messageStateNotiferProvider)
.message,
),
),
ElevatedButton(
onPressed: () {
ref
.read(MessageStatelessWidgetState
.messageStateNotiferProvider.notifier)
.updateMessage("update onPressed");
},
child: const Text("update message"),
),
],
),
);
});
}
}
関連記事
本記事の続編を書きました。
Discussion