はじめに
👆のModalBottomSheetを閉じた時に特定の処理を実行する方法として、例えば以下のようなやり方があります。
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) => const BottomSheet(),
).whenComplete(() {
print('ModalBottomSheetが閉じた');
});
whenComplete
が実行されるときに取得できるriverpodで状態管理してる値が更新されず、次の操作でwhenComplete
が実行された際に反映されるという問題に直面したのです。。。
イメージとしては
①ModalBottomSheetを開いて、その中でriverpodで状態管理してる値Aを変更する
👇
②ModalBottomSheetを閉じる
👇
③whenComplete
が実行される
👇
④値Aを使って必要なメソッドを実行(しかし値Aは①で変更した値ではなく、その前の値)
よくわからないかもですが、こんな感じですw
ファイルの構成はMVVMっぽい感じで以下の通り
・search_page.dart(view)
・search.dart(model)
・search_view_model.dart(ViewModel)
環境
hooks_riverpod + freezed + StateNotifierで状態管理をやってます
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
hooks_riverpod: ^2.0.0-dev.0
freezed_annotation: ^1.1.0
dev_dependencies:
freezed: ^1.1.1
状態が更新されていなかった時のコード
まずは思った通りの挙動にならなかった時
モデルファイル
@freezed
class Search with _$Search {
factory Search({
@Default('') String date,
}) = _Search;
}
viewファイル
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../search_provider.dart';
class SearchPage extends HookConsumerWidget {
const AreaAndCategory({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final search = ref.watch(SearchProvider);
final date = searchJob.date;
return Row(
children: [
Expanded(
child: GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) => const AreaSheet(),
).whenComplete(() {
// ref.watchによって監視されているdateがModalBottomSheetで選択した値によって変わる・・・と思っていた。。
ref
.read(SearchProvider.notifier)
.getItems(context: context, date: date);
});
}
}
処理を実行するViewModelファイル
ここの引数で受け取るdate
がModalBottomSheetで変更した値ではなかった。。。
Future<void> getItems({
required BuildContext context,
String date,
}) async {
// 何らかの処理
print(date);
}
状態が更新されていた時のコード
これで思った通りの挙動になりました!!
モデルファイル
ここは変化なし
@freezed
class Search with _$Search {
factory Search({
@Default('') String date,
}) = _Search;
}
viewファイル
getItemsメソッドに引数でdate
を渡すのをやめました!!
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../search_provider.dart';
class SearchPage extends HookConsumerWidget {
const AreaAndCategory({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Row(
children: [
Expanded(
child: GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) => const AreaSheet(),
).whenComplete(() {
// 引数をcontextだけにした
ref
.read(SearchProvider.notifier)
.getItems(context: context);
});
}
}
処理を実行するViewModelファイル
viewから引数でdate
を受け取るのではなく、StateNotifierのstate
から取得に変更
Future<void> getItems({
required BuildContext context,
}) async {
// 何らかの処理
print(state.date);
}
①ModalBottomSheetを開いて、その中でriverpodで状態管理してる値Aを変更する
👇
②ModalBottomSheetを閉じる
👇
③whenComplete
が実行される
👇
④値Aを使って必要なメソッドを実行(値Aは①で変更した値)
これで上記のような思った挙動になりました!!!
誰か原因を言語化してください