この記事で伝えたいこと
- state を更新するときは安全に更新できているかしっかり確認しよう
AsyncNotifier.build / Retry 時に全く同じメソッドを使用
もちろん同じメソッドを使用しても問題ない実装もございますが、今回の例ではマズイです。
ホームページ
class HomePage extends ConsumerWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(asyncTodosProvider);
return Scaffold(
body: state.when(
data: (data) => ListView.builder(
itemBuilder: (context, index) => ListTile(
title: Text(data[index].description),
),
itemCount: data.length,
),
error: (e, s) => Center(
child: TextButton(
onPressed: () {
ref.read(asyncTodosProvider.notifier).fetchTodo();
},
child: const Text('Retry'),
),
),
loading: () => const CircularProgressIndicator(),
),
);
}
}
riverpod_generator で実装した AsyncNotifier部分
todo.dart
@riverpod
class AsyncTodos extends _$AsyncTodos {
Future<List<Todo>> fetchTodo() async {
final todos = // List<Todo> を取得
return todos;
}
@override
FutureOr<List<Todo>> build() async {
return fetchTodo();
}
}
↑の実装では、エラーをキャッチしてくれない場合があります。その状況と原因はわかりますか?
fetch の再試行時にエラーが発生
AsyncTodos.fetchTodo
は内部的に try-catch
やAsyncValue.guard
を使用していないためエラーをキャッチしてくれません。
初期化の fetchTodo と 外部から呼ばれる fetchTodo を分離しよう
外部から呼び出せないプライベートなメソッド: _fetchTodo
外部から呼び出せるため、AsyncValue.guard
でエラーハンドリングするメソッド: fetchTodo
todo.dart
@riverpod
class AsyncTodos extends _$AsyncTodos {
Future<List<Todo>> _fetchTodo() async {
final todos = // List<Todo> を取得
return todos;
}
@override
FutureOr<List<Todo>> build() async {
return _fetchTodo();
}
Future<void> fetchTodo() async {
state = await AsyncValue.guard(_fetchTodo);
}
}
なぜ_fetchTodo
では、AsyncValue.guard
を使用していないのか
実は build 関数内で呼ばれるメソッドは、内部的に AsyncValue.guard
で実装されているのです。
安全に AsyncValue を使いこなしましょう!
参考