目的
flutter_hooks における useFuture
は、
Future インスタンスを更新しない限り非同期処理を再実行しない。
何らかのアクションをトリガーにして処理を再実行したい場合、ちょっとした工夫が必要になる。
もっとお手軽に再実行したいということで、 CustomHook を作ってみることにした。
活用サンプル
article_view.dart
class ArticleView extends HookConsumerWidget {
const ArticleView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// ⭐ future をお手軽に再評価可能な useFuture
// Future<String> fetchArticle();
final article = useReloadableFuture(() => fetchArticle());
if (!article.hasData) {
return CircularProgress();
}
return Column(
children: [
Text(article.data),
ElevatedButton(
child: const Text("Reload"),
// ボタン押下により fetchArticle() が再実行される
onPressed: () => article.reload(),
),
],
);
}
}
CustomHook の実装
use_reloadable_future.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
/// reload 可能な [AsyncSnapshot] を提供する [useFuture] のラッパー
///
/// 引数は [Future] を再生成可能な [getFuture] 関数となっている。
/// snapshot.reload() の実行によって [getFuture] が再実行される。
_ReloadableAsyncSnapshot<T> useReloadableFuture<T>(
Future<T> Function() getFuture, {
T? initialData,
bool preserveState = true,
}) {
final key = useState(1);
final future = useMemoized(getFuture, [key.value]);
final snapshot = useFuture(
future,
initialData: initialData,
preserveState: preserveState,
);
final reloadable = _ReloadableAsyncSnapshot(
snapshot,
reload: () => key.value += 1,
);
return reloadable;
}
/// [AsyncSnapshot] に対し、外部から実行可能な [reload] メソッドを加えるためだけのクラス
///
/// 外部で活用する想定はないため private でよい。
class _ReloadableAsyncSnapshot<T> extends AsyncSnapshot<T?> {
_ReloadableAsyncSnapshot(
AsyncSnapshot<T?> snapshot, {
required this.reload,
}) : super.withData(snapshot.connectionState, snapshot.data);
final void Function() reload;
}
参考文献